Token Introspection
Note
This pattern is typically referred to as token introspection. Descope implements it through the standard OIDC /userinfo endpoint, rather than a dedicated OAuth 2.0 Token Introspection endpoint (RFC 7662).
For basic JWT validation, see our Session Validation docs.
Verifying a token's signature confirms that Descope issued it and that it has not expired. It says nothing about the user's current roles, permissions, tenant, or custom attributes. Those reflect whatever was true at the moment the token was issued.
When you need the live state of the user's roles, permissions, tenant, and custom attributes on every request, you can call the UserInfo endpoint with the same access token the client sent you.
Descope will validate the token and returns the user's current claims, which you then use in your authorization logic.
Therefore, you should use token introspection with UserInfo when:
- Roles, permissions, or tenant assignments may have changed since the token was issued
- You need custom attributes or template output that are not in the JWT
- You must read the active tenant mid-session (for example, after a
switch_tenanttool call)
Note
UserInfo is not the only way to read current user state. The Management SDK or API also works, but it requires a management key, which is a privileged server credential.
UserInfo authenticates with the access token the client already sent, which is why MCP servers and third-party APIs prefer it.
It's worth noting that this pattern applies to tokens issued through Federated Applications, Inbound Apps, and Agentic Clients.
The endpoint path you use depends on which app type issued the token, and the paths are not interchangeable.
UserInfo Endpoints by App Type
Federated Applications and Inbound Apps use different UserInfo routes. Send each app type's access token to its matching endpoint.
| App type | UserInfo endpoint | Issued by | API reference |
|---|---|---|---|
| Federated Application (OIDC) | {baseUrl}/oauth2/v1/userinfo | Standard OIDC authorization code, client credentials, or device flows against a Federated App | OIDC endpoints |
| Inbound App | {baseUrl}/oauth2/v1/apps/userinfo | Inbound App /oauth2/v1/apps/token flows | Get UserInfo, Post UserInfo |
| Inbound App (project-scoped) | {baseUrl}/oauth2/v1/apps/{projectId}/userinfo | Same Inbound App tokens; path advertised in some MCP discovery documents | Same behavior as /oauth2/v1/apps/userinfo |
Replace {baseUrl} with your project base URL (for example https://api.descope.com, a regional host, or a custom domain).
Note
An access token from an Inbound App will not work against /oauth2/v1/userinfo, and a Federated Application access token will not work against /oauth2/v1/apps/userinfo.
If you are unsure which type you have, check the app's discovery document or the token issuer.
Federated Application /userinfo Endpoint
For Federated Applications configured in Applications, the OIDC UserInfo endpoint is:
GET {baseUrl}/oauth2/v1/userinfo
Authorization: Bearer <access_token>curl -X GET "https://api.descope.com/oauth2/v1/userinfo" \
-H "Authorization: Bearer <ACCESS_TOKEN>"The response includes standard OIDC profile claims, plus custom claims and tenant roles and permissions depending on the requested scopes. See Using OIDC Endpoints for the full flow.
Inbound App /userinfo Endpoint
For Inbound Apps, UserInfo lives under the /apps path:
GET {baseUrl}/oauth2/v1/apps/userinfo
Authorization: Bearer <access_token>curl -X GET "https://api.descope.com/oauth2/v1/apps/userinfo" \
-H "Authorization: Bearer <ACCESS_TOKEN>"- A successful response means Descope accepts the token for that app. Use the returned claims for authorization.
- A non-success response means the token is invalid or revoked, so reject the request.
The response reflects the user's current profile and claims as Descope resolves them for that token, following your JWT template and granted scopes.
HTTP methods: Both GET and POST are supported:
Some clients, including MCP discovery metadata, advertise the project-scoped variant {baseUrl}/oauth2/v1/apps/{projectId}/userinfo. It accepts the same Inbound App access tokens.
Operational considerations
Every UserInfo call will add a degree of latency to your validation process. If your risk model tolerates authorization data lagging Descope by some seconds or minutes, cache responses for a short TTL.
A signature-only gateway (JWT authorizers) validates tokens at the edge but does not return live claims. When your server needs current authorization data, call UserInfo. Otherwise, validate locally and accept some staleness.