Skip to content

OIDC Quickstart

This guide walks you through adding BlokSec as an OpenID Connect identity provider to your web application, from creating the application in the admin console to validating tokens, refreshing sessions, and signing out.

BlokSec implements the standard OIDC authorization code flow on top of node-oidc-provider. Any conformant OIDC client library will work. For the complete endpoint and claim reference, see the OIDC Reference.

  • Admin access to the BlokSec admin console
  • A web application that supports OIDC (most frameworks have an OIDC client library)

How you integrate depends on whether your app can keep a secret:

Client type Examples Authentication
Confidential Server-rendered apps, backends Client ID + client secret
Public Single-page apps (SPAs), native/mobile apps PKCE (no secret)

Public clients cannot safely store a secret, so they prove possession of the authorization code using PKCE instead. The steps below note where the two paths differ.

Step 1: Create an OIDC application in BlokSec

Section titled “Step 1: Create an OIDC application in BlokSec”
  1. In the admin console, go to Applications > Add Application.
  2. Enter a name for your application.
  3. Set Protocol to OpenID Connect.
  4. Set Application Type to match your app:
    • Web application — confidential client (server-rendered app or backend). BlokSec issues a client secret after creation.
    • Single-Page App (SPA) or Native app — public client (browser SPA or mobile app). Uses PKCE; no client secret is issued.
  5. Add your application’s redirect URI (e.g., https://yourapp.com/callback). It must match exactly at runtime, including scheme and path.
  6. Optionally add a post-logout redirect URI.
  7. Click Create.

After creation, note the Client ID shown on the application detail page — you’ll need it in the next step.

For a Web application, click Generate Secret on the application detail page to create a client secret. Copy it immediately; it’s only shown once. SPA and Native app clients don’t get a secret.

OIDC application creation form in the admin console
Creating an OIDC application

Step 2: Point your client at the discovery document

Section titled “Step 2: Point your client at the discovery document”

Configure your OIDC client library with BlokSec’s issuer URL and let it self-configure from the discovery document:

Issuer (authority): https://api.bloksec.io/oidc
Discovery document: https://api.bloksec.io/oidc/.well-known/openid-configuration

For the sandbox/development environment, use https://api.bloksec.dev/oidc.

The discovery document provides every endpoint your client needs. The key ones:

Endpoint URL
Authorization https://api.bloksec.io/oidc/auth
Token https://api.bloksec.io/oidc/token
UserInfo https://api.bloksec.io/oidc/me
JWKS https://api.bloksec.io/oidc/jwks
End session https://api.bloksec.io/oidc/session/end

Redirect the user to the authorization endpoint:

https://api.bloksec.io/oidc/auth?
client_id=YOUR_CLIENT_ID
&redirect_uri=https://yourapp.com/callback
&response_type=code
&scope=openid email profile
&state=RANDOM_STATE_VALUE
&nonce=RANDOM_NONCE_VALUE

Required parameters:

Parameter Description
client_id Your application’s Client ID from the admin console
redirect_uri Must match a redirect URI you registered
response_type code for the authorization code flow
scope Space-separated list of scopes; must include openid

Recommended parameters:

Parameter Description
state A random value your app generates to prevent CSRF. Verify it matches when the user returns.
nonce A random value bound into the ID token. Verify it matches after token exchange.

Public clients (SPAs and native apps) must also include PKCE:

Parameter Description
code_challenge Base64URL-encoded SHA-256 hash of a random code_verifier
code_challenge_method Must be S256

The user sees the BlokSec login screen and authenticates with their phone — no password.

After authentication, BlokSec redirects back to your redirect_uri with an authorization code:

https://yourapp.com/callback?code=AUTH_CODE&state=YOUR_STATE_VALUE

Verify state matches what you sent, then POST the code to the token endpoint. The code is valid for 10 minutes and can be used once.

Confidential client:

Terminal window
curl -X POST https://api.bloksec.io/oidc/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTH_CODE" \
-d "redirect_uri=https://yourapp.com/callback" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"

Public client (PKCE): omit client_secret and include the code_verifier that matches the code_challenge from step 3:

Terminal window
curl -X POST https://api.bloksec.io/oidc/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTH_CODE" \
-d "redirect_uri=https://yourapp.com/callback" \
-d "client_id=YOUR_CLIENT_ID" \
-d "code_verifier=YOUR_CODE_VERIFIER"

The response contains:

{
"access_token": "0pHqW8c5Rf...opaque",
"id_token": "eyJhbGci...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "8xY..."
}

The id_token is a JWT carrying the user’s identity claims. Before trusting it:

  1. Verify the signature using BlokSec’s JWKS endpoint (https://api.bloksec.io/oidc/jwks). Tokens are signed with PS256 or RS256.
  2. Check iss equals https://api.bloksec.io/oidc (including the /oidc suffix).
  3. Check aud equals your Client ID.
  4. Check exp is in the future.
  5. Check nonce matches the value you sent in step 3.

Most OIDC client libraries perform all of these checks automatically.

The ID token includes claims based on the scopes you requested:

Scope Claims included
openid sub (subject identifier), aud, amr
email email, email_verified
profile name, given_name, family_name, preferred_username, picture, upn, user_did, account
phone phone_number, phone_number_verified

See the reference for the full claim list, including BlokSec-specific claims like account (which carries the user’s roles).

To fetch the user’s profile separately from the ID token, call the UserInfo endpoint with the access token:

Terminal window
curl https://api.bloksec.io/oidc/me \
-H "Authorization: Bearer ACCESS_TOKEN"

It returns the claims granted by the token’s scopes. This is also how a resource server can resolve an opaque access token to a user identity without the introspection credentials.

Access tokens last 1 hour. To keep a session alive without sending the user back through login, use a refresh token (valid for 7 days).

To receive a refresh token, your authorization request in step 3 must include both:

  • offline_access in the scope (e.g., scope=openid email profile offline_access)
  • prompt=consent

Exchange the refresh token for a fresh access token:

Terminal window
curl -X POST https://api.bloksec.io/oidc/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=YOUR_REFRESH_TOKEN" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"

Public clients omit client_secret.

Redirect the user to the end session endpoint to terminate their BlokSec session:

https://api.bloksec.io/oidc/session/end?
id_token_hint=THE_ID_TOKEN
&client_id=YOUR_CLIENT_ID
&post_logout_redirect_uri=https://yourapp.com/

Clear your own local tokens first, then perform the redirect. The post_logout_redirect_uri must be registered on the application.

The configuration below is the one the BlokSec admin console itself uses in production. It’s a complete, working reference for a browser SPA using oidc-client-ts:

import { UserManager, WebStorageStateStore } from 'oidc-client-ts';
const userManager = new UserManager({
authority: 'https://api.bloksec.io/oidc',
client_id: 'YOUR_CLIENT_ID',
redirect_uri: `${window.location.origin}/auth/callback`,
post_logout_redirect_uri: `${window.location.origin}/auth/signin`,
response_type: 'code',
// offline_access for refresh tokens; prompt=consent is REQUIRED to get them
scope: 'openid profile email offline_access',
prompt: 'consent',
// Silent (iframe) renewal before the access token expires
silent_redirect_uri: `${window.location.origin}/auth/silent-callback`,
automaticSilentRenew: true,
loadUserInfo: true,
monitorSession: false,
userStore: new WebStorageStateStore({ store: localStorage }),
// some libraries mishandle the empty 200 revocation response; revoke via signout
revokeTokensOnSignout: false,
});

You’ll need two callback routes:

  • /auth/callback — calls userManager.signinRedirectCallback() to complete login.
  • /auth/silent-callback — a near-empty page that calls userManager.signinSilentCallback(); it renders inside a hidden iframe during renewal.

For signout, clear the user and redirect to the end session endpoint:

async function signOut() {
await userManager.removeUser();
const url = `https://api.bloksec.io/oidc/session/end`
+ `?client_id=YOUR_CLIENT_ID`
+ `&post_logout_redirect_uri=${encodeURIComponent(window.location.origin + '/auth/signin')}`;
window.location.href = url;
}

No refresh token in the response. Add prompt=consent and include offline_access in your scope. Confirm the application has the refresh_token grant type enabled.

ID token validation fails on the issuer. Set authority / the expected iss to https://api.bloksec.io/oidc, including the /oidc suffix — not the bare host.

Trying to decode the access token fails. Access tokens are opaque, not JWTs. Validate them with introspection or UserInfo, not by decoding.

Silent renewal never fires. Set automaticSilentRenew: true and make sure your silent-callback route is reachable. BlokSec always returns expires_in, which client libraries need to schedule renewal.

Errors at signout. Set revokeTokensOnSignout: false and use the end session endpoint as shown above.

  • OIDC Reference — every endpoint, all scopes and claims, token lifetimes, and error codes
  • Authentication Flow — how BlokSec’s passwordless authentication works under the hood