# Signed JWT with Certificate

The following example uses NodeJS code to show how to prepare for signed JWT authentication to an API on the BC Government API Gateway.

# 1. Generate a Certificate Key Pair

npm install --save node-jose ms

echo "
const fs = require('fs');
const jose = require('node-jose');

const keyStore = jose.JWK.createKeyStore()
keyStore.generate('RSA', 2048, {alg: 'RS256', use: 'sig' })
.then(result => {
  const [key] = keyStore.all({ use: 'sig' })
  fs.writeFileSync(
    'client.key',
    key.toPEM(true)
  )
  fs.writeFileSync(
    'client.crt',
    key.toPEM(false)
  )
  console.log('Saved to: client.key and client.crt')
})
" | node

# 2. Request Access to an API

Go to the API Services Portal and request access to an API that is configured with the Signed JWT protection. After selecting the environment, you will be prompted to provide a "Public Key", which will be the contents of the client.crt created in step 1. After requesting access, you will be provided with some secrets.

Make a note of the Client ID, Issuer and Token Endpoint.

export CID=""
export ISS=""
export TURL=""

# 3. Request a Client JWT Token

Requesting a Client JWT Token is a two-step process:

  1. Build a Client Assertion Token that is signed with the private key you generated earlier.

  2. Request a token from the Token Endpoint using the Client Assertion.

The following sample performs both steps:

npm install --save njwt node-fetch@v2

echo "
const njwt = require('njwt');

const fs = require('fs')

const privateKey = fs.readFileSync('client.key')
const clientId = process.env.CID; // Or load from configuration
const now = Math.floor( new Date().getTime() / 1000 ); // seconds since epoch
const plus5Minutes = new Date( ( now + (5*60) ) * 1000); // Date object
const alg = 'RS256'; // one of RSA or ECDSA algorithms: RS256, RS384, RS512, ES256, ES384, ES512

const claims = {
  aud: process.env.ISS
};

const jwt = njwt.create(claims, privateKey, alg)
  .setIssuedAt(now)
  .setExpiration(plus5Minutes)
  .setIssuer(clientId)
  .setSubject(clientId)
  .compact();

const fetch = require('node-fetch');
const { URLSearchParams } = require('url');

const params = new URLSearchParams();
params.append('grant_type', 'client_credentials');
params.append('client_id', process.env.CID);
params.append('scopes', 'openid');
params.append('client_assertion_type', 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer');
params.append('client_assertion', jwt);

fetch(process.env.TURL, { method: 'POST', body: params })
    .then(res => res.json())
    .then(json => console.log(json));

" | node

# 4. Call the API

Call the API using the newly generated Token returned from the Identity Provider.

curl -v https://a-protected-api.test.api.gov.bc.ca/headers \
  -H "Authorization: Bearer $TOK"