How to validate a JWT token using a JWKS (JSON) public key

2.6k Views Asked by At

I'm trying to write a service that will take a JWT token and verify it using a public key that's in the JWKS JSON format. I believe I can grab the key and convert it into a KeyObject (no idea if this is necessary), but I can't quite figure out how to convert it into whatever format verifyAsync needs, which I'm guessing is PEM format. Here's the code I have so far:

import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { KeyObject, createPublicKey } from 'crypto';

@Injectable()
export class TokenValidationService {
  constructor(
    private jwtService: JwtService
  ) { }

  async validate(token: string): Promise<any | boolean> {
    const jwt = this.jwtService.decode(token);
    if (!jwt) {
      return false;
    }

    const jwks: Response = await fetch('https://xxxxxx.auth0.com/.well-known/jwks.json');
    const jwksJson = await jwks.json();
    
    const key: KeyObject = createPublicKey({
      key: jwksJson.keys[0],
      format: 'jwk'
    })

    // TODO: Somehow convert this KeyObject into a string that verifyAsync accepts

    await this.jwtService.verifyAsync(token, {
      algorithms: ['RS256'],
      publicKey: myKeyString
    })

    return jwt;
  }
}

Any help would be appreciated.

2

There are 2 best solutions below

0
Mike Christensen On

Ok, I think I figured it out. I'd still be interested if there's a better way to go about doing this.

    const key: KeyObject = createPublicKey({
      key: jwksJson.keys[0],
      format: 'jwk'
    })

    const exportedKey: string = key.export({ type: 'pkcs1', format: 'pem' }).toString();

    const verifiedJwt = await this.jwtService.verifyAsync(token, {
      algorithms: ['RS256'],
      publicKey: exportedKey,
      ignoreExpiration: true
    })
0
Aman Desai On

Why not use something like jwks-rsa?

Example taken from: https://www.npmjs.com/package/jsonwebtoken

var jwksClient = require('jwks-rsa');
var client = jwksClient({
  jwksUri: 'https://sandrino.auth0.com/.well-known/jwks.json'
});
function getKey(header, callback){
  client.getSigningKey(header.kid, function(err, key) {
    var signingKey = key.publicKey || key.rsaPublicKey;
    callback(null, signingKey);
  });
}

jwt.verify(token, getKey, options, function(err, decoded) {
  console.log(decoded.foo) // bar
});