AutherBeta

Manual Verification

Verify a token string directly - useful for WebSockets, message queues, or any flow outside Express middleware.

auther.verify(token)

Accepts a raw token string and returns a typed result object. Use this when you have the token but are not in a standard Express request/response cycle.

typescript
const result = await auther.verify(rawToken);

if (result.ok) {
  console.log(result.user.email);
  console.log(result.user.id);
  console.log(result.user.name);  // 'Jane Doe' - or null if never given
} else {
  console.error(result.message); // e.g. 'Invalid or expired token'
}

Offline verification

verify() asks Auther about every token. auther.verifyLocal() checks the signature against our published public keys instead, so there is no round trip and it keeps working if Auther is unreachable. Needs @auther-sdk/node 1.3.0 or later.

typescript
// No network call after the first request
const result = await auther.verifyLocal(rawToken);

if (result.ok) {
  console.log(result.user.id);         // the token's subject
  console.log(result.user.projectId);
}

Choose on freshness, not speed

Local verification checks the token, not the account. A session you revoked seconds ago still passes until its access token expires, which is up to 15 minutes. verify() sees a revocation immediately. Use local checks on high-volume read paths, and keep verify() anywhere "this user was just banned" has to take effect now.

It also returns only what the token itself asserts, so there is no email or emailVerified on the result: those live on the account, and returning a cached copy would be stale data dressed up as fresh. The first call falls back to a normal API verification to learn your project id, then every call after it is offline.

Verifying without our SDK

Tokens are signed with RS256 and our public keys are published at https://oautherbackend.ziloris.com/.well-known/jwks.json, so any standard JWT library can verify them. Match the token's kid header to a key in that document.

Two things to get right. Pin the algorithm to RS256 rather than trusting the token's own alg, or someone can sign HS256 with the public key you just downloaded and your verifier will accept it. And check that the pid claim matches your project id: every project's tokens are signed by the same keys, so a signature check on its own would accept a token minted for somebody else's project.

WebSocket example

typescript
import { WebSocketServer } from 'ws';

const wss = new WebSocketServer({ port: 8080 });

wss.on('connection', async (ws, req) => {
  // Token passed as query param: ws://host?token=...
  const token = new URL(req.url!, 'http://x').searchParams.get('token');

  if (!token) { ws.close(1008, 'Unauthorized'); return; }

  const result = await auther.verify(token);
  if (!result.ok) { ws.close(1008, result.message); return; }

  // Authenticated - attach user to socket
  (ws as any).user = result.user;
  ws.send(JSON.stringify({ type: 'connected', userId: result.user.id }));
});

Return type

typescript
type VerifyResult =
  | { ok: true;  user: AutherUser }
  | { ok: false; status: number; message: string };

Same verification, different interface

auther.verify() calls the exact same Auther backend endpoint as auther.protect(). The only difference is that you handle the result yourself instead of the middleware doing it.