File size: 2,119 Bytes
c0dd699
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import { CacheHandler } from '../../types';
import { JwksError, SigningKeyNotFoundError } from './errors';
import { retrieveSigningKeys } from './utils';

const logger = console.log;

export class JwksClient {
	options: any;
	constructor(options: { jwksUri: string; cacheHandler: CacheHandler }) {
		this.options = {
			...options,
		};
	}

	async getKeys() {
		try {
			const cachedKeys = await this.options.cacheHandler.get(this.options.jwksUri);
			let keys;
			if (cachedKeys) {
				logger('Keys retrieved from cache: ');
				keys = JSON.parse(cachedKeys);
			} else {
				logger(`Fetching keys from '${this.options.jwksUri}': `);
				const res = (await fetch(this.options.jwksUri, {}).then((res) => res.json())) as { keys: [] };
				this.options.cacheHandler.set(this.options.jwksUri, JSON.stringify(res.keys));
				keys = res.keys;
			}
			logger(keys);
			return keys;
		} catch (err: any) {
			const { errorMsg } = err;
			logger('Failure:', errorMsg || err);
			throw errorMsg ? new JwksError(errorMsg) : err;
		}
	}

	async getSigningKeys() {
		const keys = await this.getKeys();
		if (!keys || !keys.length) {
			throw new JwksError('The JWKS endpoint did not contain any keys');
		}

		const signingKeys = await retrieveSigningKeys(keys);

		if (!signingKeys.length) {
			throw new JwksError('The JWKS endpoint did not contain any signing keys');
		}

		logger('Signing Keys:', signingKeys);
		return signingKeys;
	}

	async getSigningKey(kid: string) {
		logger(`Fetching signing key for '${kid}'`);
		const keys = await this.getSigningKeys();

		const kidDefined = kid !== undefined && kid !== null;
		if (!kidDefined && keys.length > 1) {
			logger('No KID specified and JWKS endpoint returned more than 1 key');
			throw new SigningKeyNotFoundError('No KID specified and JWKS endpoint returned more than 1 key');
		}

		const key = keys.find((k: { kid?: string }) => !kidDefined || k.kid === kid);
		if (key) {
			return key;
		} else {
			logger(`Unable to find a signing key that matches '${kid}'`);
			throw new SigningKeyNotFoundError(`Unable to find a signing key that matches '${kid}'`);
		}
	}
}