Integrate
Verifying access tokens
Check your users' access tokens offline, with your app's public keys (RS256).
How tokens are signed
Every access token Identise hands your app is signed RS256 with a key of your app's own, which only Identise holds. Your services verify tokens with that key's public half, from /apps/{appId}/.well-known/jwks.json, so they need no secret at all.
Your API key is only for your backend's calls to Identise: keep it on those servers, and out of every service that only checks tokens.
What to check
| Algorithm | Only RS256. |
| Key | The one the token's kid header names, from your app's JWKS. |
aud | Your App ID. |
iss | Your Identise deployment's issuer: the issuer in your app's /apps/{appId}/.well-known/openid-configuration. |
exp | Required. No clock skew needed: the tokens last minutes (15 by default). |
Claims
sub | The user's id. Use it as your foreign key, not the email. |
email | The user's email. |
email_verified, mfa_enabled | The strings "true" or "false". |
status | Active, PendingVerification or Suspended. |
Verifying tokens
Point your JWT library at the keys and pin the algorithm. The libraries below cache the keys and fetch them again when a token names one they haven't seen.
ASP.NET Core
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
// Your app's own authority: finds its keys through /.well-known/openid-configuration below it,
// caches them, and fetches them again when a token names a key it hasn't seen
options.Authority = $"https://api.identise.com/apps/{identise.AppId}";
options.MapInboundClaims = false;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = identise.Issuer,
ValidAudience = identise.AppId,
ValidAlgorithms = [SecurityAlgorithms.RsaSha256],
ClockSkew = TimeSpan.Zero
};
});Node (jose)
import { createRemoteJWKSet, jwtVerify } from "jose";
// Your app's own keys: fetched on first use, cached, and fetched again when a token names a key it hasn't seen
const identiseKeys = createRemoteJWKSet(
new URL(`https://api.identise.com/apps/${process.env.IDENTISE_APP_ID}/.well-known/jwks.json`),
);
export async function verifyIdentiseToken(token: string) {
const { payload } = await jwtVerify(token, identiseKeys, {
algorithms: ["RS256"],
audience: process.env.IDENTISE_APP_ID,
issuer: process.env.IDENTISE_ISSUER,
});
return { userId: payload.sub!, email: payload.email as string, emailVerified: payload.email_verified === "true" };
}Python (PyJWT)
import jwt
identise_keys = jwt.PyJWKClient(f"https://api.identise.com/apps/{IDENTISE_APP_ID}/.well-known/jwks.json")
def verify_identise_token(token):
key = identise_keys.get_signing_key_from_jwt(token)
return jwt.decode(token, key.key, algorithms=["RS256"], audience=IDENTISE_APP_ID, issuer=IDENTISE_ISSUER)Your app's keys
Every app has keys of its own, held by Identise: another app's tokens never verify with yours.
| Where | https://api.identise.com/apps/{appId}/.well-known/jwks.json: public, cacheable for 5 minutes. An App ID that doesn't exist is a 404. |
| Rotation | A key signs for 90 days. The next one is published from the start, and a replaced key stays published 24 hours after, so every token you meet has a key you have already fetched. |
| Revoking an API key | Revoking, rotating or deleting one of your API keys (or your app being suspended) hands over to the next signing key at once and stops publishing the old one. Tokens issued before then, perhaps by someone holding a leaked key, stop verifying as soon as your service fetches the JWKS again: restart it, or clear its key cache, to cut them off at once. New tokens use a key you already have. |
| Discovery | /apps/{appId}/.well-known/openid-configuration gives the issuer, the jwks_uri and the claims, for libraries that start from an authority: use https://api.identise.com/apps/{appId}. |
Rotating an API key
Tokens don't depend on your API key, so rotate it whenever you like:
- 1
Generate the new key
In the dashboard, under the app's API Keys.
- 2
Deploy it
To every server that calls Identise.
- 3
Revoke the old key
Your app's signing key hands over with it, so access tokens issued before stop verifying once your services fetch the JWKS again; your users simply refresh.
none, never let a token's own alg header choose how it is checked, and never skip the aud check: it is what stops one app's tokens from working in another.