Token introspection
POST /oauth/introspect implements RFC 7662. Use it to ask “is this token still valid right now” — useful for sensitive operations where catching revocation immediately matters more than the extra round-trip.
When to use introspection vs offline JWT
| Offline (JWKS) | Introspection | |
|---|---|---|
| Latency | ~0ms | ~50ms |
| Catches revocation | ❌ until exp | ✅ immediately |
| Catches expiry | ✅ | ✅ |
| Use for | Every authenticated read | Payments, role grants, admin actions |
Combine: validate offline on every request and introspect on the operations you can’t afford to be wrong about. Subscribe to session.revoked webhooks to invalidate your session cache proactively (see Handling revocation).
Endpoint
POST https://api.trymellonauth.com/oauth/introspect
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded
token=$JWT&token_type_hint=access_token
Response (active):
{
"active": true,
"sub": "user_abc",
"aud": "client_xyz",
"iss": "https://api.trymellonauth.com",
"iat": 1717000000,
"exp": 1717003600,
"client_id": "client_xyz",
"scope": "openid"
}
Response (inactive — revoked, expired, malformed, or unknown):
{ "active": false }
Per RFC 7662, active: false is the only signal you should rely on for inactive tokens — no further fields are guaranteed.
cURL
curl -X POST https://api.trymellonauth.com/oauth/introspect \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d "token=$TOKEN" \
-d "token_type_hint=access_token"
Node.js helper
const credentials = Buffer.from(
`${process.env.TRYMELLON_CLIENT_ID}:${process.env.TRYMELLON_CLIENT_SECRET}`,
).toString('base64');
export async function isActive(token: string): Promise<boolean> {
const res = await fetch('https://api.trymellonauth.com/oauth/introspect', {
method: 'POST',
headers: {
Authorization: `Basic ${credentials}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({ token, token_type_hint: 'access_token' }),
});
if (!res.ok) return false;
const body = await res.json() as { active: boolean };
return body.active;
}
Cost considerations
Introspection is a synchronous network call. At high throughput, calling it on every request adds latency and pressure on the API. Recommended pattern:
- Verify offline on every request (fast).
- Maintain a short-lived deny list in your cache (Redis SET with TTL = remaining token lifetime).
- Add to deny list when
session.revokedwebhook arrives. - Optionally introspect on sensitive operations as a belt-and-suspenders check.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 Unauthorized | Wrong Basic Auth credentials. | Confirm client_id:client_secret, base64-encoded, in Authorization: Basic …. |
active: false immediately | Token was issued for a different application. | Confirm the introspecting app’s client_id matches the token’s aud. |
INTROSPECTION_FAILED (SDK) | Endpoint returned 5xx or network error. | Treat as inactive; retry with backoff. |