Skip to content

OIDC Reference

Complete reference for BlokSec’s OpenID Connect implementation. For a step-by-step integration guide, see the OIDC Quickstart.

BlokSec’s provider is built on node-oidc-provider and implements the standard OpenID Connect and OAuth 2.0 endpoints. The fastest way to integrate is to point a standard OIDC client library at the discovery document and let it configure itself.

Each environment is a separate issuer. Use the base URL that matches the environment your application targets.

Environment Base URL Issuer (iss)
Production https://api.bloksec.io https://api.bloksec.io/oidc
Sandbox / development https://api.bloksec.dev https://api.bloksec.dev/oidc

All OIDC endpoints live under the /oidc path. The rest of this page uses the production base URL; substitute the sandbox URL for testing.

GET /oidc/.well-known/openid-configuration

Returns the full OIDC discovery document with all endpoint URLs, supported scopes, grant types, claims, and signing algorithms. Most OIDC client libraries use this endpoint for automatic configuration — you give them the issuer URL and they fetch everything else.

When you create an application in the BlokSec admin console, you choose a type: Web application, Single-Page App (SPA), or Native app. The type determines whether BlokSec treats your client as confidential or public, what credentials it issues, and which token endpoint authentication methods are available.

A server-side app running in a trusted environment (Node.js, .NET, Python, etc.) where the client secret never leaves the server. BlokSec issues a client secret and treats it as a confidential client.

Use this type when:

  • Your callback handler runs on a server you control
  • You need refresh tokens for long-lived sessions
  • You want the strongest token endpoint authentication options (JWT assertions, mTLS)

A browser-only JavaScript app where no server-side component can hold a secret. BlokSec creates a public client — no client secret is issued. PKCE (S256) is required in place of client authentication.

Use this type when:

  • Your callback runs entirely in the browser (React, Vue, Angular, etc.)
  • You cannot keep a secret out of the browser bundle or DevTools
  • Redirect URIs use https

A mobile or desktop application. Like a SPA, it is a public client — no secret is issued and PKCE is required. Redirect URIs can be custom URI scheme (e.g. com.example.app://callback) or loopback (http://127.0.0.1).

Use this type when:

  • Your app runs on iOS, Android, macOS, Windows, or Linux
  • You need to use a custom scheme or loopback redirect URI
Web application SPA Native app
Client type Confidential Public Public
Client secret Yes No No
PKCE required No (recommended) Yes (S256) Yes (S256)
Refresh tokens Yes (offline_access + prompt=consent) Yes (offline_access + prompt=consent) Yes (offline_access + prompt=consent)
Typical redirect URI https://yourapp.com/callback https://yourapp.com/callback Custom scheme or loopback
token_endpoint_auth_method client_secret_basic (default), client_secret_post, client_secret_jwt, private_key_jwt, tls_client_certificate none none
GET /oidc/auth

Starts the authentication flow. Redirect the user’s browser to this endpoint.

Parameter Required Description
client_id Yes Application’s Client ID (a DID, assigned when you create the application)
redirect_uri Yes Must exactly match a redirect URI registered on the application
response_type Yes code for the authorization code flow
scope Yes Space-separated scopes (must include openid)
state Recommended Opaque value echoed back to your callback for CSRF protection
nonce Recommended Random value bound into the ID token; verify it after token exchange
prompt Conditional login forces re-authentication; consent forces the consent screen. Required to obtain a refresh token — see Refresh tokens
code_challenge Public clients S256 PKCE challenge (required when token_endpoint_auth_method is none)
code_challenge_method Public clients Must be S256

On success, redirects to redirect_uri with:

  • code — authorization code, valid for 10 minutes and usable once
  • state — echo of your state parameter

On failure, redirects with error and error_description query parameters.

POST /oidc/token
Content-Type: application/x-www-form-urlencoded

Exchanges an authorization code, refresh token, or client credentials for tokens. Confidential clients authenticate here; the default method is client_secret_basic (HTTP Basic auth with the Client ID and secret), and client_secret_post is also accepted.

Parameter Required Description
grant_type Yes authorization_code
code Yes The authorization code from the callback
redirect_uri Yes Must match the redirect_uri from the authorization request
client_id Yes Application’s Client ID
client_secret Confidential clients Application’s client secret
code_verifier Public clients The PKCE verifier whose challenge was sent to the authorization endpoint
Parameter Required Description
grant_type Yes refresh_token
refresh_token Yes A previously issued refresh token
client_id Yes Application’s Client ID
client_secret Confidential clients Application’s client secret
scope No A subset of the originally granted scopes

For machine-to-machine authentication where the application acts as itself, with no user involved.

Parameter Required Description
grant_type Yes client_credentials
client_id Yes Application’s Client ID
client_secret Yes Application’s client secret
scope No Requested scopes
{
"access_token": "0pHqW8c5Rf...opaque",
"id_token": "eyJhbGci...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "8xY...",
"scope": "openid email profile offline_access"
}
  • access_token — an opaque token (see Token formats). Present it as a Bearer token to BlokSec endpoints; do not attempt to decode it.
  • id_token — a signed JWT containing the user’s identity claims.
  • expires_in — always present, so client libraries can schedule renewal. client_credentials responses do not include id_token or refresh_token.
GET /oidc/me
Authorization: Bearer {access_token}

Returns claims about the authenticated user, filtered by the scopes the access token was granted. This is the standard way for a client to fetch the user’s profile after login.

{
"sub": "did:bloksec:abc123",
"email": "user@example.com",
"email_verified": true,
"given_name": "Jane",
"family_name": "Smith",
"name": "Jane Smith",
"preferred_username": "jane",
"upn": "jane",
"user_did": "did:bloksec:abc123"
}
GET /oidc/jwks

Returns the JSON Web Key Set used to sign ID tokens. Use these keys to verify ID token signatures. Access tokens are opaque and have no signature to verify — validate them with introspection or UserInfo instead.

GET /oidc/session/end

RP-initiated logout. Redirect the user’s browser here to end their BlokSec session. After logout, BlokSec redirects back to post_logout_redirect_uri if one is supplied and registered.

Parameter Required Description
id_token_hint Recommended The ID token issued to the client, identifying the session to end
client_id Recommended Application’s Client ID
post_logout_redirect_uri No Must match a registered post-logout redirect URI
state No Echoed back on the redirect
Endpoint Method Description
/oidc/token/introspection POST Token introspection (RFC 7662) — returns token metadata and an active flag
/oidc/token/revocation POST Token revocation (RFC 7009)

Because access tokens are opaque, a resource server validates them by calling the introspection endpoint:

POST /oidc/token/introspection
Content-Type: application/x-www-form-urlencoded
token={access_token}

A confidential client authenticates with HTTP Basic auth. A public client may introspect only tokens that were issued to itself. The response includes:

{
"active": true,
"client_id": "did:bloksec:abc123",
"sub": "did:bloksec:user456",
"scope": "openid email profile",
"exp": 1619704640,
"iat": 1619701040
}

If the token is invalid, expired, or revoked, active is false and no other fields are returned.

Scope Claims included
openid sub, aud, amr (required for every request)
email email, email_verified
profile name, given_name, family_name, middle_name, nickname, preferred_username, picture, profile, website, gender, birthdate, zoneinfo, locale, updated_at, upn, user_did, user_short_code, account
phone phone_number, phone_number_verified
offline_access No claims — grants a refresh token (see below)

Standard JWT claims (iss, aud, exp, iat, auth_time, sid, nonce, amr) appear in the ID token regardless of scope.

In the admin console, the application’s Scopes setting (on the application form) controls which of these scopes the app is permitted to request. A request for a scope the application isn’t allowed to use is ignored.

Claim Description
account JSON-encoded object with account-specific data, including the user’s roles for this application
upn User Principal Name (typically the account name)
user_did The user’s Decentralized Identifier
user_short_code Short code identifying the user-client relationship

The admin console can show you the exact claims your application will receive for a real account — without running a full login flow. This is the fastest way to confirm your scope configuration produces the claims your app expects.

On the application’s detail page (available once the app has been created), click Preview ID Token, then select an account. BlokSec renders the ID token claims that account would receive given the application’s configured scopes, and lists the active scopes used. A Copy button copies the JSON.

Preview ID Token dialog showing an account selector and the resulting ID token claims
Previewing the ID token claims for a selected account

Example claims for an app with the openid email profile scopes granted:

{
"sub": "did:bloksec:account_abc123",
"aud": "your-client-id",
"email": "jane@example.com",
"email_verified": true,
"account": "{}",
"preferred_username": "jane@example.com",
"upn": "jane@example.com",
"name": "Jane Smith",
"given_name": "Jane",
"family_name": "Smith",
"user_did": "did:bloksec:user_def456",
"user_short_code": "Lz1ZG"
}
Token Format How to validate
ID token Signed JWT (PS256 or RS256) Verify the signature against the JWKS endpoint, then check iss, aud, exp, and nonce
Access token Opaque string Call introspection or UserInfo; do not decode
Refresh token Opaque string Exchange at the token endpoint
Token Lifetime
Access token 1 hour
ID token 1 hour
Authorization code 10 minutes
Client credentials token 10 minutes
Refresh token 7 days
Session 1 hour
Grant (consent) 14 days
Grant type Description
authorization_code Standard browser-based login (default)
refresh_token Exchange a refresh token for a new access token
client_credentials Server-to-server authentication, no user

An application must have a grant type enabled on its configuration to use it. By default, applications are created with authorization_code, refresh_token, and client_credentials.

To receive a refresh token, two conditions must hold:

  1. The application has the refresh_token grant type enabled (the default).
  2. The authorization request includes scope=...offline_access and prompt=consent.

The prompt=consent parameter is the most commonly missed setting. The OpenID Connect spec requires it when requesting offline_access, and without it the provider drops offline_access from the request and returns no refresh token.

Method Used by
client_secret_basic Confidential clients (default) — Client ID and secret via HTTP Basic auth
client_secret_post Confidential clients — credentials in the form body
client_secret_jwt, private_key_jwt Confidential clients using signed JWT client assertions
none Public clients (SPAs, native apps) — PKCE is required instead

Advanced: token endpoint authentication methods

Section titled “Advanced: token endpoint authentication methods”

These methods apply to Web application (confidential) clients only. SPA and Native clients always use none (PKCE handles their security instead).

client_secret_basic (default) The client ID and secret are base64-encoded and sent in the Authorization: Basic ... header. This is the standard HTTP Basic authentication scheme and the default for all new Web application clients.

Authorization: Basic base64(client_id:client_secret)

client_secret_post The client ID and secret are included as form body parameters (client_id and client_secret) rather than a header. Useful when the HTTP client or proxy cannot set custom Authorization headers.

client_secret_jwt The client creates a JWT signed with an HMAC algorithm using the client secret as the key, and sends it as a client_assertion parameter (with client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer). This proves possession of the secret without transmitting it directly.

private_key_jwt The strongest option. The client signs the assertion JWT with its own private key; BlokSec verifies it with the corresponding public key registered on the application. No shared secret exists between client and server — the private key never leaves the client.

tls_client_certificate The client authenticates via a mutual-TLS certificate presented during the TLS handshake. The certificate must be registered on the application. Best suited for high-security server environments with certificate infrastructure already in place.

PKCE (Proof Key for Code Exchange) is required for public clients — those whose token_endpoint_auth_method is none. Only the S256 challenge method is supported. Confidential clients may use PKCE but are not required to.

ID tokens are signed with PS256 or RS256. Fetch the public keys from the JWKS endpoint to verify signatures.

Token endpoint errors follow RFC 6749:

{
"error": "invalid_grant",
"error_description": "Authorization code has expired"
}

Common errors:

Error Meaning
invalid_client Client authentication failed (bad ID or secret)
invalid_grant Authorization code or refresh token is invalid, expired, or already used
invalid_request A required parameter is missing or malformed
invalid_scope A requested scope is unknown or not allowed for this client
unauthorized_client The client is not authorized for the requested grant type

UserInfo and other Bearer-protected endpoints return:

Error Meaning
invalid_token The access token is missing, expired, or revoked
insufficient_scope The access token lacks a scope required for the request