A Singapore Government Agency Website

OAuth 2.1 Sample Codes

Want to see these steps in context? Follow the OAuth 2.1 interactive walkthrough.

These sample codes are for reference only and are not intended for production use.

Generate Code Challenge and Code Verifier

'use strict';

const crypto = require('crypto');

function generateCodeVerifier() {
  return crypto.randomBytes(32).toString('base64url');
}

function generateCodeChallenge(codeVerifier) {
  return crypto.createHash('sha256').update(codeVerifier).digest('base64url');
}

const codeVerifier = generateCodeVerifier();
const codeChallenge = generateCodeChallenge(codeVerifier);

console.log('Code Verifier:', codeVerifier);
console.log('Code Challenge:', codeChallenge);

Generate JWKS Endpoint

'use strict';

const jose = require('node-jose');
const crypto = require('crypto');

async function jwks() {
    let key = crypto.generateKeyPairSync('ec', {
      namedCurve: 'prime256v1',
      publicKeyEncoding: {
        type: 'spki',
        format: 'pem',
      },
      privateKeyEncoding: {
        type: 'pkcs8',
        format: 'pem',
      },
    });

    let cryptoKey = await jose.JWK.asKey(key.privateKey, 'pem');

    let publicKeyJSON = cryptoKey.toJSON();

    let jwksEndpoint = {
      keys: [{
        ...publicKeyJSON,
        use: "sig",
        crv: "P-256",
        alg: "ES256",
      }]
    };

    console.log("Public keys:");
    console.log(publicKeyJSON);

    console.log("JWKS Endpoint:");
    console.log(jwksEndpoint);
}
jwks();

Sample Output

Public keys:
{
  "kty": "EC",
  "kid": "vyaeBP-ohJ5RF_cEEU1v0h3IEIoWCa24YKZK4ddb4-U",
  "crv": "P-256",
  "x": "RYvFyXBZLa7TWEDlk3sqqyhxXkTYGkEEl5AuANZ70Ps",
  "y": "JKobI-7Z4xBCGDKDubtBF-sHvC69F6sKGbRX3RIaGhY"
}
JWKS Endpoint:
{
  "keys": [
    {
      "kty": "EC",
      "kid": "vyaeBP-ohJ5RF_cEEU1v0h3IEIoWCa24YKZK4ddb4-U",
      "crv": "P-256",
      "x": "RYvFyXBZLa7TWEDlk3sqqyhxXkTYGkEEl5AuANZ70Ps",
      "y": "JKobI-7Z4xBCGDKDubtBF-sHvC69F6sKGbRX3RIaGhY",
      "use": "sig",
      "alg": "ES256"
    }
  ]
}

Generate Client Assertion

The client assertion is a JWT signed with your ES256 private key that proves your application’s identity during the token exchange.

'use strict';

const jwt = require('jsonwebtoken');
const fs = require('fs');

const epoch = new Date().getTime();

let payload = {};

let privateKey = fs.readFileSync('./private.key', 'utf8');

let signOptions = {
  issuer: 'STG-xxxx',       // Your Client ID issued during Initial Setup
  subject: 'STG-xxxx',      // Your Client ID issued during Initial Setup
  audience: 'https://public.api.gov.sg/oauth/cp/v3/token',
  jwtid: `session-${epoch}`, // Unique session ID for troubleshooting and preventing replay attacks
  keyid: 'key-id1',          // Your key ID in JWKS endpoint from Initial Setup
  expiresIn: '5m',
  algorithm: 'ES256'
};

let clientAssertion = jwt.sign(payload, privateKey, signOptions);
console.log('Client Assertion:', clientAssertion);
Claim Value
iss Your Client ID.
sub Your Client ID.
aud The Token Endpoint URL (e.g. https://public.api.gov.sg/oauth/cp/v3/token).
kid Key ID of the signing key in your JWKS endpoint.
jti A unique identifier for this token request (e.g. session ID with epoch).
exp Expiry time — must not exceed 5 minutes from iat.
Chat with me!
Bot Launcher