UNPKG

1.87 kBJavaScriptView Raw
1import * as error from '../error.js'
2import * as buffer from '../buffer.js'
3import * as string from '../string.js'
4import * as json from '../json.js'
5import * as ecdsa from '../crypto/ecdsa.js'
6
7/**
8 * @param {Object} data
9 */
10const _stringify = data => buffer.toBase64UrlEncoded(string.encodeUtf8(json.stringify(data)))
11
12/**
13 * @param {string} base64url
14 */
15const _parse = base64url => json.parse(string.decodeUtf8(buffer.fromBase64UrlEncoded(base64url)))
16
17/**
18 * @param {CryptoKey} privateKey
19 * @param {Object} payload
20 */
21export const encodeJwt = (privateKey, payload) => {
22 const { name: algName, namedCurve: algCurve } = /** @type {any} */ (privateKey.algorithm)
23 /* c8 ignore next 3 */
24 if (algName !== 'ECDSA' || algCurve !== 'P-384') {
25 error.unexpectedCase()
26 }
27 const header = {
28 alg: 'ES384',
29 typ: 'JWT'
30 }
31 const jwt = _stringify(header) + '.' + _stringify(payload)
32 return ecdsa.sign(privateKey, string.encodeUtf8(jwt)).then(signature =>
33 jwt + '.' + buffer.toBase64UrlEncoded(signature)
34 )
35}
36
37/**
38 * @param {CryptoKey} publicKey
39 * @param {string} jwt
40 */
41export const verifyJwt = async (publicKey, jwt) => {
42 const [headerBase64, payloadBase64, signatureBase64] = jwt.split('.')
43 const verified = await ecdsa.verify(publicKey, buffer.fromBase64UrlEncoded(signatureBase64), string.encodeUtf8(headerBase64 + '.' + payloadBase64))
44 /* c8 ignore next 3 */
45 if (!verified) {
46 throw new Error('Invalid JWT')
47 }
48 return {
49 header: _parse(headerBase64),
50 payload: _parse(payloadBase64)
51 }
52}
53
54/**
55 * Decode a jwt without verifying it. Probably a bad idea to use this. Only use if you know the jwt was already verified!
56 *
57 * @param {string} jwt
58 */
59export const unsafeDecode = jwt => {
60 const [headerBase64, payloadBase64] = jwt.split('.')
61 return {
62 header: _parse(headerBase64),
63 payload: _parse(payloadBase64)
64 }
65}