Descope OIDC Endpoints Quickstart

Using Descope as an OpenID Connect (OIDC) provider is a common integration path—especially when your framework does not have a native Descope SDK (for example Expo, .NET Blazor, or custom OAuth clients).

This guide explains how to use Descope's OIDC endpoints to authenticate users, obtain tokens, manage sessions, and perform secure logout and token revocation.

Core OIDC Endpoints

PurposeEndpoint
Authorization - Start the OIDC login flowhttps://api.descope.com/oauth2/v1/authorize
Token - Exchange authorization codes for tokenshttps://api.descope.com/oauth2/v1/token
UserInfo - Retrieve user claims and profile informationhttps://api.descope.com/oauth2/v1/userinfo
JWKs URI - Retrieve public keys for verifying Descope-issued JWTshttps://api.descope.com/__ProjectID__/.well-known/jwks.json
End Session - Log the user out of their Descope sessionhttps://api.descope.com/oauth2/v1/logout
Revocation - Revoke a token (access or refresh)https://api.descope.com/oauth2/v1/revoke

Diagram of OIDC Authorization Code Flow

ApplicationBrowser / UserDescope (IdP)redirect to /authorizeGET /authorizeauth flow runsredirect with codecallback with codePOST /token (code + client_secret)validates tokensid_token + access_token

Confidential server-side apps use a client secret at the token endpoint.

  • Redirect the user to /authorize with client_id set to your Project ID.
  • Exchange the authorization code at /token using a Descope Access Key as client_secret.
  • Descope returns an id_token, access_token, and refresh_token.
1 / 3

Supported Grant Types

Descope supports the following OAuth 2.0 grant types:

  • Authorization Code Flow with PKCE - Recommended for public clients (SPAs, native mobile)
  • Authorization Code Flow (without PKCE) - For confidential clients that can safely store a client secret
  • Client Credentials Flow - For machine-to-machine (M2M) integrations
  • Device Authorization Flow - For devices without a browser or keyboard (e.g., smart TVs)

The sections below walk through each flow in detail.

Authorization Code Flow (with PKCE)

Use this flow when building native mobile apps, SPAs, or any public client that cannot safely store a client secret. PKCE (Proof Key for Code Exchange) protects against code interception attacks.

1. Generate a Code Verifier and Code Challenge

function generateCodeVerifier() {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
  return Array.from(crypto.getRandomValues(new Uint8Array(128)))
    .map(x => chars[x % chars.length])
    .join('');
}

async function generateCodeChallenge(verifier) {
  const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
  return btoa(String.fromCharCode(...new Uint8Array(digest)))
    .replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
}

2. Redirect the User to the Authorization Endpoint

const authUrl = `https://api.descope.com/oauth2/v1/authorize
  ?response_type=code
  &client_id=__ProjectID__
  &redirect_uri=YOUR_REDIRECT_URI
  &scope=openid profile email
  &code_challenge=${codeChallenge}
  &code_challenge_method=S256
  &state=YOUR_STATE`;

window.location.href = authUrl;

After successful authentication, Descope redirects to your redirect_uri with an authorization code.

3. Exchange the Authorization Code for Tokens

const response = await fetch('https://api.descope.com/oauth2/v1/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code: 'AUTHORIZATION_CODE',
    redirect_uri: 'YOUR_REDIRECT_URI',
    client_id: '__ProjectID__',
    code_verifier: codeVerifier,
  }),
});
const tokens = await response.json();

4. Retrieve User Information

const userResponse = await fetch('https://api.descope.com/oauth2/v1/userinfo', {
  headers: { 'Authorization': `Bearer ${tokens.access_token}` },
});
const user = await userResponse.json();

The /userinfo response includes user claims (for example email, name, sub) along with any custom claims and role assignments you have configured in Descope.

Tip

Store the refresh_token securely in your application so you can obtain new access tokens without forcing the user to log in again.

Authorization Code Flow (without PKCE)

Confidential clients (such as server-side web apps and trusted backend services) can perform the Authorization Code flow without PKCE by authenticating with their client secret.

Note

We still recommend enabling PKCE wherever possible. However, some enterprise OIDC clients expect the classic authorization code flow with a client secret and no PKCE. This section shows how to support that scenario.

1. Redirect the User to the Authorization Endpoint

https://api.descope.com/oauth2/v1/authorize?
  response_type=code&
  client_id=__ProjectID__&
  redirect_uri=https://your-app.com/callback&
  scope=openid%20profile%20email&
  state=YOUR_STATE

2. Exchange the Authorization Code for Tokens

Send the authorization code to the token endpoint. Include your client secret in either the Authorization header or the POST body.

curl -X POST https://api.descope.com/oauth2/v1/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -u '__ProjectID__:YOUR_CLIENT_SECRET' \
  -d 'grant_type=authorization_code' \
  -d 'code=AUTHORIZATION_CODE' \
  -d 'redirect_uri=https://your-app.com/callback'

The response includes the access_token, id_token, and optionally a refresh_token. Use the access_token to call /userinfo, and verify the id_token signature before establishing a session.

Security reminder

Only use this approach when you can safely store and protect the client secret. For SPAs or mobile apps, always use the PKCE variant.

Client Credentials Flow (Machine-to-Machine)

Use the Client Credentials flow to obtain tokens for backend services without user interaction.

  1. Generate an Access Key in the Descope Console.
  2. Combine the <Client ID> and <Access Key> as <ClientID>:<AccessKey>.
  3. Base64-encode the string and send it in the Authorization header.
curl -X POST https://api.descope.com/oauth2/v1/token \
  -H 'Authorization: Basic <BASE64(<ClientID>:<AccessKey>)>' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=client_credentials&scope=openid%20profile%20email'

Custom claims for machine-to-machine tokens can be configured using Access Key JWT Templates under Project Settings.

Managing Sessions and Tokens

Logout vs Token Revocation

ActionAffectsWhen to Use
/logoutUser session (browser)Sign the user out from Descope and your app
/revokeSpecific tokenInvalidate tokens programmatically

End Session (/logout)

window.location.href = `https://api.descope.com/oauth2/v1/logout
  ?id_token_hint=${id_token}
  &post_logout_redirect_uri=${YOUR_REDIRECT_URL}`;

Revocation (/revoke)

await fetch('https://api.descope.com/oauth2/v1/revoke', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    token: 'TOKEN_TO_REVOKE',
    client_id: '__ProjectID__',
  }),
});

Silent Authentication

Silent authentication lets you refresh sessions without prompting the user, as long as they still have an active Descope session.

https://api.descope.com/oauth2/v1/authorize?...&prompt=none

Common scenarios include SPAs refreshing tokens or background session renewal.

Passing Dynamic Values into Flows

When redirecting to /authorize, you can include additional query parameters and consume them inside your Descope flow with a Scriptlet:

const query = new URL(startUrl).searchParams;
return {
  age: query.get('age'),
  plan: query.get('plan'),
};

These values are available for conditions, screens, or custom logic inside the flow.

JWT Verification

To verify any JWT (such as id_token or access_token), retrieve Descope's public keys from the JWKs endpoint:

https://api.descope.com/__ProjectID__/.well-known/jwks.json

Use these keys to validate signatures and confirm token authenticity in your backend.

Testing the Endpoints

You can experiment with Descope's OIDC endpoints using OAuth Tools or your preferred API client. This is useful for validating flows, refreshing tokens, and checking error responses.

With these endpoints and grant types, you can integrate Descope into any framework or custom OIDC client while maintaining the same level of security, observability, and user experience provided by Descope flows.

Was this helpful?

On this page