1. Overview
The SSO JWT Portal issues short-lived Access Tokens as JSON Web Tokens signed with RS256 (RSA, asymmetric). Your application — the Relying App — never needs the private key. Instead, you fetch the portal's public key and use it to cryptographically verify the signature, issuer, and expiry of each token presented to you.
| Property | Value |
|---|---|
| Signing algorithm | RS256 |
Issuer (iss) | sso.demo.dakok.net |
Subject (sub) | User identifier |
Authorized apps (apps) | Array of application ids the user may access |
| Access token lifetime | 15 minutes (exp - iat = 900) |
Key identifier (kid) | In the token header; selects the matching public key |
2. Public key endpoints
Both endpoints are public (no authentication) and served over HTTPS. Pick whichever format your framework supports.
JWKS endpoint
GET https://sso.demo.dakok.net/.well-known/jwks.json
Returns a JSON Web Key Set. During key rotation it can contain more than one key, so always resolve the
correct key by the token header's kid.
// example JWKS response { "keys": [ { "kty": "RSA", "use": "sig", "alg": "RS256", "kid": "2f1c...a9", "n": "<base64url modulus>", "e": "AQAB" } ] }
PEM endpoint
GET https://sso.demo.dakok.net/api/keys/public.pem
Returns the active public key in PEM format (a -----BEGIN PUBLIC KEY-----
block). Convenient for libraries that take a PEM string directly.
kid-based resolution and cache keys with a short TTL so newly rotated keys are
picked up automatically. The previous public key stays published until all tokens it signed have expired
(≤ 15 minutes).
3. Token & refresh model
- Access Token — RS256 JWT, lifetime 15 minutes. Send it to your Relying App (for example as
Authorization: Bearer <token>) and verify it on every request. - Refresh Token — lifetime 14 days, single-use with rotation. Calling
POST /api/auth/refreshreturns a new access token and a new refresh token, and invalidates the old refresh token. Reusing a rotated, revoked, or expired refresh token returns401. - Logout revokes the refresh token so it can no longer be used.
As a Relying App you typically only verify the access token. Refresh and logout are handled by the portal itself; you do not need the private key or any secret to verify tokens.
4. Verify with JWKS (Node.js)
Using jose, which fetches and caches the JWKS and resolves the key by
kid automatically:
// npm install jose import { jwtVerify, createRemoteJWKSet } from 'jose'; const JWKS = createRemoteJWKSet( new URL('https://sso.demo.dakok.net/.well-known/jwks.json') ); export async function verifyAccessToken(token) { const { payload } = await jwtVerify(token, JWKS, { issuer: 'sso.demo.dakok.net', // checks iss algorithms: ['RS256'], // pin the algorithm }); // jwtVerify also validates exp (and nbf/iat) automatically. return payload; // { iss, sub, iat, exp, apps: [...] } }
Alternatively, with jwks-rsa + jsonwebtoken:
// npm install jwks-rsa jsonwebtoken const jwt = require('jsonwebtoken'); const jwksClient = require('jwks-rsa'); const client = jwksClient({ jwksUri: 'https://sso.demo.dakok.net/.well-known/jwks.json', cache: true, rateLimit: true, }); function getKey(header, callback) { // resolve the signing key by the token header's kid client.getSigningKey(header.kid, (err, key) => { if (err) return callback(err); callback(null, key.getPublicKey()); }); } function verifyAccessToken(token) { return new Promise((resolve, reject) => { jwt.verify( token, getKey, { algorithms: ['RS256'], issuer: 'sso.demo.dakok.net' }, (err, decoded) => (err ? reject(err) : resolve(decoded)) ); }); }
5. Verify with PEM (Node.js)
If you prefer the single active public key in PEM form:
// npm install jsonwebtoken const jwt = require('jsonwebtoken'); async function loadPublicPem() { const res = await fetch('https://sso.demo.dakok.net/api/keys/public.pem'); return res.text(); // -----BEGIN PUBLIC KEY----- ... } async function verifyAccessToken(token) { const publicPem = await loadPublicPem(); return jwt.verify(token, publicPem, { algorithms: ['RS256'], issuer: 'sso.demo.dakok.net', }); }
6. Generic verification checklist
Whatever language or library you use, a correct verification does all of the following:
- Parse the JWT header and read the
kid. - Fetch the public key set from the JWKS endpoint and select the key whose
kidmatches (or use the PEM active key). - Verify the signature using RS256 — and pin the algorithm so a token can't downgrade it
(reject
alg: noneand HMAC algorithms). - Check
issequalssso.demo.dakok.net. - Check
expis in the future (token not expired); reject if expired. - Read
sub(the user) andapps(authorized application ids) and enforce that your application id is present inapps.
algorithms: ['RS256']. Accepting any algorithm is a
common JWT vulnerability.
7. MCP server for AI integration
The portal exposes a Model Context Protocol (MCP) server at POST https://sso.demo.dakok.net/mcp (JSON-RPC) so tools like Kiro can integrate programmatically while building Relying Apps.
| Tool type | Auth | Examples |
|---|---|---|
| Read-only (open) | No API key required | Fetch public key (PEM), JWKS, application list, token-verification details (JWKS URL, PEM URL,
alg=RS256, iss=sso.demo.dakok.net) |
| Write / management (gated) | Requires a valid, non-expired API key | Management operations that change state |
To use write tools, sign in to the portal and claim an API key. The key:
- is bound to your user identifier;
- is valid for 3 hours after issuance;
- does not auto-renew — claim a new one from the portal after it expires.
Read-only tools never require a key, so AI integrations can always discover the verification details above without authenticating.