# Validate tokens to protect your APIs

All user tokens returned by Mosaic should be validated, as described below. This helps guard your endpoints and ensure users have indeed authenticated with Mosaic before you can proceed with granting them access to resources. Note, that client app tokens and management app tokens are consumed and validated by Mosaic, you don't need to validate them.

The validation process depends on your [token signing key configuration](/guides/user/token_signing_keys). Mosaic supports different signing strategies (Global signing key, app-specific keys, or BYOK), and the JWKS endpoint you use for validation varies accordingly.

## Token structure

Tokens issued by Mosaic include:

- The issuer in the `iss` (issuer) claim. Its format depends on your [signing key configuration](/guides/user/token_signing_keys):
  - **Global signing key**: The issuer is tenant-level (for example, `https://userid.security` for US, `https://eu.userid.security` for EU, `https://ca.userid.security` for CA, or `https://au.userid.security` for AU)
  - **App-specific signing keys**: The issuer is the app's unique domain (subdomain or custom domain) as configured in your application settings (for example, `https://acme-corporation.app.transmitsecurity.io`)
- A `kid` (key ID) header referencing the correct key.


ID token encryption
Mosaic returns ID tokens in encrypted (JWE) form if the client enforces ID token encryption in its settings. In this case, use your private key to decrypt the token first.

### Example ID Token

The following decoded ID token illustrates how signing is reflected in the token structure:

**Header**:


```json
{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "appkey-7f439c13"
}
```

**Payload**:


```json
{
  "iss": "https://acme-corporation.app.transmitsecurity.io",
  "sub": "user-12345",
  "aud": "client-67890",
  "exp": 1723588800,
  "iat": 1723585200,
  "auth_time": 1723585190,
  "email": "user@example.com",
  "name": "User Example"
}
```

## Verify token signatures

Verify that the token is signed by Mosaic. To do it, retrieve the public key from the JWKS endpoint. The endpoint you use depends on your [signing key configuration](/guides/user/token_signing_keys):

- **Global signing key**: Use the generic endpoint `https://api.transmitsecurity.io/cis/oidc/jwks`
- **App-specific signing keys**: Derive the endpoint from the token's `iss` claim using `${iss}/oidc/jwks` (for example, if `iss` is `https://acme-corporation.app.transmitsecurity.io`, the JWKS endpoint is `https://acme-corporation.app.transmitsecurity.io/oidc/jwks`)


The endpoint returns a set of keys, along with a name, algorithm used, etc. for each key.


```shell
# Example for Global signing key
curl -i -X GET \
  https://api.transmitsecurity.io/cis/oidc/jwks
```

Check the `kid` in the token header–it helps identify the key used to sign this particular token. Then locate the key with the same `kid` in the key array returned by JWKS response to find the right key to compare the signature against. Mismatching signatures might indicate that the token could have been stolen and replaced by bad actors.

Note
Instead of querying public keys every time you need to validate an ID or access token, consider caching a response returned by `/oidc/jwks`. It helps avoid reaching API rate limits and prevent latency issues. Signing keys don't change often. However, if token validation fails, try clearing the cache and fetching new keys before revalidating the token signature.

## Token validation best practices

When validating tokens, follow these best practices:

- **Determine the JWKS endpoint**:
  - For [Global signing key](/guides/user/token_signing_keys#global-signing-key), use `https://api.transmitsecurity.io/cis/oidc/jwks`
  - For [app-specific signing keys](/guides/user/token_signing_keys#app-specific-signing-keys), derive it from the token's `iss` claim using `${iss}/oidc/jwks`
- Select the correct public key using the `kid` in the JWT header
- Implement fallback behavior for key rotation if your system enforces strict verification


Note
You can also discover the correct JWKS URI dynamically from the `jwks_uri` field at:
`${iss}/.well-known/openid-configuration`

For information on managing token signing keys and key rotation, see [Token signing keys](/guides/user/token_signing_keys).

## Validate user access tokens

Important
User access tokens must be validated on your side if you plan on using them to authorize internal API calls. If you plan on passing these tokens to other services, they should validate tokens as well.

Validate access tokens returned upon successful authentication or fetched for API authorization, as follows:

- Validate that the issuer of the access token (`iss`) matches the expected issuer:
  - For [Global signing key](/guides/user/token_signing_keys#global-signing-key): `https://userid.security` (for US tenants), `https://eu.userid.security` (for EU tenants), `https://ca.userid.security` (for CA tenants), or `https://au.userid.security` (for AU tenants)
  - For [app-specific signing keys](/guides/user/token_signing_keys#app-specific-signing-keys): The issuer is the app's unique domain as configured in your application settings (for example, `https://acme-corporation.app.transmitsecurity.io`)
- Validate that the expiry time (`exp`) of the access token has not passed
- Validate that the tenant ID (`tid`) corresponds to your tenant
- Validate the audience (`aud`) if you want to limit access to a specific [resource](/guides/user/manage_resources). The access token will only include the resource in the `aud` claim if the client it's issued for is connected to this resource.
- Validate that `sub` corresponds to the user identity stored in Mosaic.
- Validate that the client ID (`client_id`) corresponds to the application client ID stored in Transmit
- Validate that roles (`roles`) correspond to the roles assigned to the user


See [User access tokens](/openapi/user_access_tokens) for more details on token claims.

## Validate ID tokens

Validate ID tokens returned upon successful authentication as follows:

- Validate that the issuer of the ID token (`iss`) matches the expected issuer:
  - For [Global signing key](/guides/user/token_signing_keys#global-signing-key): `https://userid.security` for US, `https://eu.userid.security` for EU, `https://ca.userid.security` for CA, or `https://au.userid.security`  for AU.
  - For [app-specific signing keys](/guides/user/token_signing_keys#app-specific-signing-keys): The issuer is the app's unique domain as configured in your application settings (for example, `https://acme-corporation.app.transmitsecurity.io`)
- Validate that the audience of the ID token (`aud`) is equal to the client ID related to the authentication
- Validate that the expiry time (`exp`) of the ID token has not passed
- Validate that the tenant ID (`tid`) corresponds to your tenant


See [ID tokens](/openapi/id_token_reference) for more details on ID token claims.