# Verify identity tokens on your server

Your app sends the user's access token to your backend as `Authorization: Bearer <token>`. The token is an ES256 JWT that lasts fifteen minutes. Its issuer is `<IDENTITY_ISSUER>/projects/<projectId>`, its audience is the project ID, and it carries the user ID (`sub`), the session family (`sid`), the workspace (`wid`) and, when set, your own user ID (`ext`).

Both verifiers check the signature against the project's public keys (`GET /v1/identity/jwks`, fetched and cached), the ES256 algorithm, issuer, audience and expiry. Verification is networkless after the keys are cached. A verified token proves the person signed in when it was issued. It cannot show a revocation, such as a logout or a block, before it expires; to see that, call `GET /me` with the token.

The defaults point at Mocco's hosted service (`https://www.mocco.club`). On a self-hosted server, pass your `IDENTITY_ISSUER` as the issuer.

## Node

```ts
import { createIdentityVerifier } from '@mocco/node';

const verifier = createIdentityVerifier({ projectId: 'your-project-uuid' });

// Anywhere you have a Request, Headers or a plain header object:
const user = await verifier.authenticate(request);
if (user === null) {
  return new Response('Unauthorized', { status: 401 });
}
console.log(user.userId, user.externalId, user.expiresAt);
```

`authenticate` reads the `Authorization` header and returns the claims, or `null` for a missing header, an API key (`mk_…`) or a token that fails verification. It never throws for a bad token. `verify(token)` takes the bare token and rejects when it fails. Claims are `userId`, `sessionId`, `workspaceId`, `projectId`, `externalId` (`null` when unset) and `expiresAt`. Build one verifier and share it, so the key cache is shared.

## Rust

```rust
use mocco_identity::{Verifier, VerifierConfig};

let verifier = Verifier::new(VerifierConfig {
    project_id: "your-project-uuid".to_owned(),
    issuer: None,
    jwks_url: None,
});

match verifier.verify(token).await {
    Ok(claims) => println!("signed in as {}", claims.user_id),
    Err(error) => println!("rejected: {error}"),
}
```

With the `axum` feature, a `MoccoUser` extractor reads the header and answers `401` for anything that does not verify. The [crate's README](https://github.com/fi-workers/mocco/blob/main/packages/sdk-rust/mocco-identity/README.md) covers the errors, the key cache and custom key fetching. The crate is published manually for now.

## When to ask Mocco instead

Use the verifier for routes where a fifteen-minute window is acceptable. For an action that must stop the moment a person is signed out or blocked, such as a payment or a deletion, also call `GET /v1/identity/me` with the token and your publishable key. It checks the live session and answers `401 invalid_session` when it has been revoked.
