Comparing version 6.4.0 to 6.5.0
@@ -7,3 +7,3 @@ import SimpleSigner from './signers/SimpleSigner'; | ||
import { EdDSASigner } from './signers/EdDSASigner'; | ||
import { verifyJWT, createJWT, decodeJWT, verifyJWS, createJWS, Signer, JWTHeader, JWTPayload, JWTVerified } from './JWT'; | ||
import { createJWS, createJWT, decodeJWT, JWTHeader, JWTPayload, JWTVerified, Signer, verifyJWS, verifyJWT } from './JWT'; | ||
import { toEthereumAddress } from './Digest'; | ||
@@ -16,2 +16,3 @@ export { JWE, createJWE, decryptJWE, Encrypter, Decrypter, ProtectedHeader, Recipient, RecipientHeader } from './JWE'; | ||
export { base64ToBytes, base58ToBytes, hexToBytes } from './util'; | ||
export * from './Errors'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -27,2 +27,5 @@ import type { DIDResolutionResult, Resolvable, VerificationMethod } from 'did-resolver'; | ||
} | ||
/** | ||
* Overrides the different types of checks performed on the JWT besides the signature check | ||
*/ | ||
export interface JWTVerifyPolicies { | ||
@@ -33,2 +36,3 @@ now?: number; | ||
exp?: boolean; | ||
aud?: boolean; | ||
} | ||
@@ -70,8 +74,34 @@ export interface JWSCreationOptions { | ||
} | ||
/** | ||
* Result object returned by {@link verifyJWT} | ||
*/ | ||
export interface JWTVerified { | ||
/** | ||
* Set to true for a JWT that passes all the required checks minus any verification overrides. | ||
*/ | ||
verified: true; | ||
/** | ||
* The decoded JWT payload | ||
*/ | ||
payload: Partial<JWTPayload>; | ||
/** | ||
* The result of resolving the issuer DID | ||
*/ | ||
didResolutionResult: DIDResolutionResult; | ||
/** | ||
* the issuer DID | ||
*/ | ||
issuer: string; | ||
/** | ||
* The public key of the issuer that matches the JWT signature | ||
*/ | ||
signer: VerificationMethod; | ||
/** | ||
* The original JWT that was verified | ||
*/ | ||
jwt: string; | ||
/** | ||
* Any overrides that were used during verification | ||
*/ | ||
policies?: JWTVerifyPolicies; | ||
} | ||
@@ -84,8 +114,2 @@ export interface PublicKeyTypes { | ||
export declare const SELF_ISSUED_V0_1 = "https://self-issued.me"; | ||
export declare const INVALID_JWT = "invalid_jwt"; | ||
export declare const INAVLID_CONFIG = "invalid_config"; | ||
export declare const INVALID_SIGNATURE = "invalid_signature"; | ||
export declare const NOT_SUPPORTED = "not_supported"; | ||
export declare const NO_SUITABLE_KEYS = "no_suitable_keys"; | ||
export declare const RESOLVE_ERROR = "resolve_error"; | ||
export declare const NBF_SKEW = 300; | ||
@@ -119,3 +143,4 @@ /** @module did-jwt/JWT */ | ||
/** | ||
* Creates a signed JWT given an address which becomes the issuer, a signer, and a payload for which the signature is over. | ||
* Creates a signed JWT given an address which becomes the issuer, a signer, and a payload for which the signature is | ||
* over. | ||
* | ||
@@ -131,8 +156,9 @@ * @example | ||
* @param {String} options.issuer The DID of the issuer (signer) of JWT | ||
* @param {String} options.alg [DEPRECATED] The JWT signing algorithm to use. Supports: [ES256K, ES256K-R, Ed25519, EdDSA], Defaults to: ES256K. | ||
* Please use `header.alg` to specify the algorithm | ||
* @param {String} options.alg [DEPRECATED] The JWT signing algorithm to use. Supports: | ||
* [ES256K, ES256K-R, Ed25519, EdDSA], Defaults to: ES256K. Please use `header.alg` to specify the algorithm | ||
* @param {Signer} options.signer a `Signer` function, Please see `ES256KSigner` or `EdDSASigner` | ||
* @param {boolean} options.canonicalize optional flag to canonicalize header and payload before signing | ||
* @param {Object} header optional object to specify or customize the JWT header | ||
* @return {Promise<Object, Error>} a promise which resolves with a signed JSON Web Token or rejects with an error | ||
* @return {Promise<Object, Error>} a promise which resolves with a signed JSON Web Token or | ||
* rejects with an error | ||
*/ | ||
@@ -154,26 +180,35 @@ export declare function createJWT(payload: Partial<JWTPayload>, { issuer, signer, alg, expiresIn, canonicalize }: JWTOptions, header?: Partial<JWTHeader>): Promise<string>; | ||
* Verifies given JWT. If the JWT is valid, the promise returns an object including the JWT, the payload of the JWT, | ||
* and the did doc of the issuer of the JWT. | ||
* and the DID document of the issuer of the JWT. | ||
* | ||
* @example | ||
* verifyJWT('did:uport:eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJyZXF1Z....', {audience: '5A8bRWU3F7j3REx3vkJ...', callbackUrl: 'https://...'}).then(obj => { | ||
* const did = obj.did // DID of signer | ||
* const payload = obj.payload | ||
* const doc = obj.doc // DID Document of signer | ||
* const jwt = obj.jwt | ||
* const signerKeyId = obj.signerKeyId // ID of key in DID document that signed JWT | ||
* ... | ||
* }) | ||
* ```ts | ||
* verifyJWT( | ||
* 'did:uport:eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJyZXF1Z....', | ||
* {audience: '5A8bRWU3F7j3REx3vkJ...', callbackUrl: 'https://...'} | ||
* ).then(obj => { | ||
* const did = obj.did // DID of signer | ||
* const payload = obj.payload | ||
* const doc = obj.didResolutionResult.didDocument // DID Document of issuer | ||
* const jwt = obj.jwt | ||
* const signerKeyId = obj.signer.id // ID of key in DID document that signed JWT | ||
* ... | ||
* }) | ||
* ``` | ||
* | ||
* @param {String} jwt a JSON Web Token to verify | ||
* @param {Object} [options] an unsigned credential object | ||
* @param {Boolean} options.auth Require signer to be listed in the authentication section of the DID document (for Authentication purposes) | ||
* @param {Boolean} options.auth Require signer to be listed in the authentication section of the | ||
* DID document (for Authentication purposes) | ||
* @param {String} options.audience DID of the recipient of the JWT | ||
* @param {String} options.callbackUrl callback url in JWT | ||
* @return {Promise<Object, Error>} a promise which resolves with a response object or rejects with an error | ||
* @return {Promise<Object, Error>} a promise which resolves with a response object or rejects with an | ||
* error | ||
*/ | ||
export declare function verifyJWT(jwt: string, options?: JWTVerifyOptions): Promise<JWTVerified>; | ||
/** | ||
* Resolves relevant public keys or other authenticating material used to verify signature from the DID document of provided DID | ||
* Resolves relevant public keys or other authenticating material used to verify signature from the DID document of | ||
* provided DID | ||
* | ||
* @example | ||
* ```ts | ||
* resolveAuthenticator(resolver, 'ES256K', 'did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX').then(obj => { | ||
@@ -183,11 +218,15 @@ * const payload = obj.payload | ||
* const jwt = obj.jwt | ||
* ... | ||
* // ... | ||
* }) | ||
* ``` | ||
* | ||
* @param {String} alg a JWT algorithm | ||
* @param {String} did a Decentralized IDentifier (DID) to lookup | ||
* @param {Boolean} auth Restrict public keys to ones specifically listed in the 'authentication' section of DID document | ||
* @return {Promise<DIDAuthenticator>} a promise which resolves with a response object containing an array of authenticators or if non exist rejects with an error | ||
* @param resolver - {Resolvable} a DID resolver function that can obtain the `DIDDocument` for the `issuer` | ||
* @param alg - {String} a JWT algorithm | ||
* @param issuer - {String} a Decentralized Identifier (DID) to lookup | ||
* @param proofPurpose - {ProofPurposeTypes} *Optional* Use the verificationMethod linked in that section of the | ||
* issuer DID document | ||
* @return {Promise<DIDAuthenticator>} a promise which resolves with an object containing an array of authenticators | ||
* or rejects with an error if none exist | ||
*/ | ||
export declare function resolveAuthenticator(resolver: Resolvable, alg: string, issuer: string, proofPurpose?: ProofPurposeTypes): Promise<DIDAuthenticator>; | ||
//# sourceMappingURL=JWT.d.ts.map |
{ | ||
"name": "did-jwt", | ||
"version": "6.4.0", | ||
"version": "6.5.0", | ||
"description": "Library for Signing and Verifying JWTs that use DIDs as issuers and JWEs that use DIDs as recipients", | ||
@@ -61,4 +61,4 @@ "type": "module", | ||
"devDependencies": { | ||
"@babel/core": "7.18.6", | ||
"@babel/preset-env": "7.18.6", | ||
"@babel/core": "7.18.10", | ||
"@babel/preset-env": "7.18.10", | ||
"@babel/preset-typescript": "7.18.6", | ||
@@ -69,13 +69,13 @@ "@ethersproject/address": "5.6.1", | ||
"@types/elliptic": "6.4.14", | ||
"@types/jest": "28.1.4", | ||
"@typescript-eslint/eslint-plugin": "5.30.5", | ||
"@typescript-eslint/parser": "5.30.5", | ||
"@types/jest": "28.1.6", | ||
"@typescript-eslint/eslint-plugin": "5.33.0", | ||
"@typescript-eslint/parser": "5.33.0", | ||
"codecov": "3.8.3", | ||
"eslint": "8.19.0", | ||
"eslint": "8.22.0", | ||
"eslint-config-prettier": "8.5.0", | ||
"eslint-plugin-jest": "26.5.3", | ||
"eslint-plugin-jest": "26.8.2", | ||
"eslint-plugin-prettier": "4.2.1", | ||
"jest": "28.1.2", | ||
"jest": "28.1.3", | ||
"jsontokens": "3.1.1", | ||
"microbundle": "0.15.0", | ||
"microbundle": "0.15.1", | ||
"mockdate": "3.0.5", | ||
@@ -87,3 +87,3 @@ "prettier": "2.7.1", | ||
"typescript": "4.7.4", | ||
"webpack": "5.73.0", | ||
"webpack": "5.74.0", | ||
"webpack-cli": "4.10.0" | ||
@@ -90,0 +90,0 @@ }, |
[![npm](https://img.shields.io/npm/dt/did-jwt.svg)](https://www.npmjs.com/package/did-jwt) | ||
[![npm](https://img.shields.io/npm/v/did-jwt.svg)](https://www.npmjs.com/package/did-jwt) | ||
[![Twitter Follow](https://img.shields.io/twitter/follow/uport_me.svg?style=social&label=Follow)](https://twitter.com/uport_me) | ||
[![Twitter Follow](https://img.shields.io/twitter/follow/veramolabs.svg?style=social&label=Follow)](https://twitter.com/veramolabs) | ||
[![codecov](https://codecov.io/gh/decentralized-identity/did-jwt/branch/master/graph/badge.svg)](https://codecov.io/gh/decentralized-identity/did-jwt) | ||
@@ -17,3 +17,3 @@ | ||
All DID methods that can be resolved using the [`did-resolver'](https://github.com/decentralized-identity/did-resolver) | ||
All DID methods that can be resolved using the [`did-resolver`](https://github.com/decentralized-identity/did-resolver) | ||
interface are supported for verification. | ||
@@ -39,11 +39,12 @@ | ||
In practice, you must secure the key passed to ES256KSigner. The key provided in code below is for informational | ||
In practice, you must secure the key passed to `ES256KSigner`. The key provided in code below is for informational | ||
purposes only. | ||
```js | ||
const didJWT = require('did-jwt') | ||
```ts | ||
import didJWT from 'did-jwt'; | ||
const signer = didJWT.ES256KSigner(didJWT.hexToBytes('278a5de700e29faae8e40e366ec5012b5ec63d36ec77e8a2417154cc1d25383f')) | ||
let jwt = await didJWT.createJWT( | ||
{ aud: 'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74', exp: 1957463421, name: 'uPort Developer' }, | ||
{ aud: 'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74', iat: undefined, name: 'uPort Developer' }, | ||
{ issuer: 'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74', signer }, | ||
@@ -67,8 +68,6 @@ { alg: 'ES256K' } | ||
```js | ||
{ | ||
header: { typ: 'JWT', alg: 'ES256K' }, | ||
```ts | ||
expect(decoded).toEqual({ | ||
header: { alg: 'ES256K', typ: 'JWT' }, | ||
payload: { | ||
iat: 1571692233, | ||
exp: 1957463421, | ||
aud: 'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74', | ||
@@ -78,5 +77,5 @@ name: 'uPort Developer', | ||
}, | ||
signature: 'kkSmdNE9Xbiql_KCg3IptuJotm08pSEeCOICBCN_4YcgyzFc4wIfBdDQcz76eE-z7xUR3IBb6-r-lRfSJcHMiAA', | ||
data: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJpYXQiOjE1NzE2OTIyMzMsImV4cCI6MTk1NzQ2MzQyMSwiYXVkIjoiZGlkOmV0aHI6MHhmM2JlYWMzMGM0OThkOWUyNjg2NWYzNGZjYWE1N2RiYjkzNWIwZDc0IiwibmFtZSI6InVQb3J0IERldmVsb3BlciIsImlzcyI6ImRpZDpldGhyOjB4ZjNiZWFjMzBjNDk4ZDllMjY4NjVmMzRmY2FhNTdkYmI5MzViMGQ3NCJ9' | ||
} | ||
signature: 'mAhpAnw-9u57hyAaDufj2GPMbmuZyPDlU7aYSUMKk7P_9_cF3iLk-hFjFhb5xaUQB5nXYrciw6ZJ2RSAZI-IDQ', | ||
data: 'eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJkaWQ6ZXRocjoweGYzYmVhYzMwYzQ5OGQ5ZTI2ODY1ZjM0ZmNhYTU3ZGJiOTM1YjBkNzQiLCJuYW1lIjoidVBvcnQgRGV2ZWxvcGVyIiwiaXNzIjoiZGlkOmV0aHI6MHhmM2JlYWMzMGM0OThkOWUyNjg2NWYzNGZjYWE1N2RiYjkzNWIwZDc0In0' | ||
}) | ||
``` | ||
@@ -95,10 +94,10 @@ | ||
```js | ||
const Resolver = require('did-resolver') | ||
const ethrDid = require('ethr-did-resolver').getResolver({ rpcUrl: 'https://mainnet.infura.io/v3/...' }) | ||
import {Resolver} from 'did-resolver'; | ||
import {getResolver} from 'ethr-did-resolver' | ||
let resolver = new Resolver.Resolver(ethrDid) | ||
let resolver = new Resolver({...getResolver({infuraProjectId: '<get a free ID from infura.io>'})}); | ||
// pass the JWT from step 1 | ||
// use the JWT from step 1 | ||
let verificationResponse = await didJWT.verifyJWT(jwt, { | ||
resolver: resolver, | ||
resolver, | ||
audience: 'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74' | ||
@@ -112,6 +111,4 @@ }) | ||
```typescript | ||
{ | ||
expect(verificationResponse).toEqual({ | ||
payload: { | ||
iat: 1571692448, | ||
exp: 1957463421, | ||
aud: 'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74', | ||
@@ -123,8 +120,23 @@ name: 'uPort Developer', | ||
didDocumentMetadata: {}, | ||
didResolutionMetadata: {}, | ||
didResolutionMetadata: { contentType: 'application/did+ld+json' }, | ||
didDocument: { | ||
'@context': 'https://w3id.org/did/v1', | ||
'@context': [ | ||
'https://www.w3.org/ns/did/v1', | ||
'https://w3id.org/security/suites/secp256k1recovery-2020/v2' | ||
], | ||
id: 'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74', | ||
publicKey: [ [Object] ], | ||
authentication: [ [Object] ] | ||
verificationMethod: [ | ||
{ | ||
id: 'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74#controller', | ||
type: 'EcdsaSecp256k1RecoveryMethod2020', | ||
controller: 'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74', | ||
blockchainAccountId: 'eip155:1:0xF3beAC30C498D9E26865F34fCAa57dBB935b0D74' | ||
} | ||
], | ||
authentication: [ | ||
'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74#controller' | ||
], | ||
assertionMethod: [ | ||
'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74#controller' | ||
] | ||
} | ||
@@ -134,9 +146,10 @@ }, | ||
signer: { | ||
id: 'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74#owner', | ||
type: 'Secp256k1VerificationKey2018', | ||
owner: 'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74', | ||
ethereumAddress: '0xf3beac30c498d9e26865f34fcaa57dbb935b0d74' | ||
id: 'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74#controller', | ||
type: 'EcdsaSecp256k1RecoveryMethod2020', | ||
controller: 'did:ethr:0xf3beac30c498d9e26865f34fcaa57dbb935b0d74', | ||
blockchainAccountId: 'eip155:1:0xF3beAC30C498D9E26865F34fCAa57dBB935b0D74' | ||
}, | ||
jwt: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJpYXQiOjE1NzE2OTI0NDgsImV4cCI6MTk1NzQ2MzQyMSwiYXVkIjoiZGlkOmV0aHI6MHhmM2JlYWMzMGM0OThkOWUyNjg2NWYzNGZjYWE1N2RiYjkzNWIwZDc0IiwibmFtZSI6InVQb3J0IERldmVsb3BlciIsImlzcyI6ImRpZDpldGhyOjB4ZjNiZWFjMzBjNDk4ZDllMjY4NjVmMzRmY2FhNTdkYmI5MzViMGQ3NCJ9.xd_CSWukS6rK8y7GVvyH_c5yRsDXojM6BuKaf1ZMg0fsgpSBioS7jBfyk4ZZvS0iuFu4u4_771_PNWvmsvaZQQE' | ||
} | ||
jwt: 'eyJhbGciOiJFUzI1NksiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJkaWQ6ZXRocjoweGYzYmVhYzMwYzQ5OGQ5ZTI2ODY1ZjM0ZmNhYTU3ZGJiOTM1YjBkNzQiLCJuYW1lIjoidVBvcnQgRGV2ZWxvcGVyIiwiaXNzIjoiZGlkOmV0aHI6MHhmM2JlYWMzMGM0OThkOWUyNjg2NWYzNGZjYWE1N2RiYjkzNWIwZDc0In0.mAhpAnw-9u57hyAaDufj2GPMbmuZyPDlU7aYSUMKk7P_9_cF3iLk-hFjFhb5xaUQB5nXYrciw6ZJ2RSAZI-IDQ', | ||
policies: {} | ||
}) | ||
``` |
@@ -471,3 +471,6 @@ import { hexToBytes, base64ToBytes } from '../util' | ||
{ requested: ['name', 'phone'], nbf: new Date().getTime() + 1000000 }, | ||
{ issuer: did, signer } | ||
{ | ||
issuer: did, | ||
signer, | ||
} | ||
) | ||
@@ -486,3 +489,6 @@ expect(verifier.verify(jwt)).toBe(true) | ||
{ requested: ['name', 'phone'], nbf: new Date().getTime() + 10000 }, | ||
{ issuer: did, signer } | ||
{ | ||
issuer: did, | ||
signer, | ||
} | ||
) | ||
@@ -694,2 +700,13 @@ expect(verifier.verify(jwt)).toBe(true) | ||
it('accepts invalid audience when override policy is used', async () => { | ||
expect.assertions(2) | ||
const jwt = await createJWT({ aud }, { issuer: did, signer }) | ||
const { payload, issuer } = await verifyJWT(jwt, { | ||
resolver, | ||
policies: { aud: false }, | ||
}) | ||
expect(payload).toBeDefined() | ||
expect(issuer).toEqual(did) | ||
}) | ||
it('rejects an invalid audience using callback_url where callback is wrong', async () => { | ||
@@ -696,0 +713,0 @@ expect.assertions(1) |
@@ -8,13 +8,14 @@ import SimpleSigner from './signers/SimpleSigner' | ||
import { | ||
verifyJWT, | ||
createJWS, | ||
createJWT, | ||
decodeJWT, | ||
verifyJWS, | ||
createJWS, | ||
Signer, | ||
JWTHeader, | ||
JWTPayload, | ||
JWTVerified, | ||
Signer, | ||
verifyJWS, | ||
verifyJWT, | ||
} from './JWT' | ||
import { toEthereumAddress } from './Digest' | ||
export { JWE, createJWE, decryptJWE, Encrypter, Decrypter, ProtectedHeader, Recipient, RecipientHeader } from './JWE' | ||
@@ -58,1 +59,3 @@ export { ECDH, createX25519ECDH } from './ECDH' | ||
export { base64ToBytes, base58ToBytes, hexToBytes } from './util' | ||
export * from './Errors' |
173
src/JWT.ts
@@ -6,2 +6,3 @@ import canonicalizeData from 'canonicalize' | ||
import VerifierAlgorithm from './VerifierAlgorithm' | ||
import { JWT_ERROR } from './Errors' | ||
@@ -41,7 +42,16 @@ export type Signer = (data: string | Uint8Array) => Promise<EcdsaSignature | string> | ||
/** | ||
* Overrides the different types of checks performed on the JWT besides the signature check | ||
*/ | ||
export interface JWTVerifyPolicies { | ||
// overrides the timestamp against which the validity interval is checked | ||
now?: number | ||
// when set to false, the timestamp checks ignore the Not Before(`nbf`) property | ||
nbf?: boolean | ||
// when set to false, the timestamp checks ignore the Issued At(`iat`) property | ||
iat?: boolean | ||
// when set to false, the timestamp checks ignore the Expires At(`exp`) property | ||
exp?: boolean | ||
// when set to false, the JWT audience check is skipped | ||
aud?: boolean | ||
} | ||
@@ -62,2 +72,3 @@ | ||
alg: string | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
@@ -75,2 +86,3 @@ [x: string]: any | ||
rexp?: number | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
@@ -94,8 +106,40 @@ [x: string]: any | ||
/** | ||
* Result object returned by {@link verifyJWT} | ||
*/ | ||
export interface JWTVerified { | ||
/** | ||
* Set to true for a JWT that passes all the required checks minus any verification overrides. | ||
*/ | ||
verified: true | ||
/** | ||
* The decoded JWT payload | ||
*/ | ||
payload: Partial<JWTPayload> | ||
/** | ||
* The result of resolving the issuer DID | ||
*/ | ||
didResolutionResult: DIDResolutionResult | ||
/** | ||
* the issuer DID | ||
*/ | ||
issuer: string | ||
/** | ||
* The public key of the issuer that matches the JWT signature | ||
*/ | ||
signer: VerificationMethod | ||
/** | ||
* The original JWT that was verified | ||
*/ | ||
jwt: string | ||
/** | ||
* Any overrides that were used during verification | ||
*/ | ||
policies?: JWTVerifyPolicies | ||
} | ||
@@ -106,2 +150,3 @@ | ||
} | ||
export const SUPPORTED_PUBLIC_KEY_TYPES: PublicKeyTypes = { | ||
@@ -115,11 +160,14 @@ ES256K: [ | ||
/** | ||
* @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is not an ethereumAddress | ||
* @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is | ||
* not an ethereumAddress | ||
*/ | ||
'Secp256k1VerificationKey2018', | ||
/** | ||
* @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is not an ethereumAddress | ||
* @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is | ||
* not an ethereumAddress | ||
*/ | ||
'Secp256k1SignatureVerificationKey2018', | ||
/** | ||
* @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is not an ethereumAddress | ||
* @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is | ||
* not an ethereumAddress | ||
*/ | ||
@@ -135,11 +183,14 @@ 'EcdsaPublicKeySecp256k1', | ||
/** | ||
* @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is not an ethereumAddress | ||
* @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is | ||
* not an ethereumAddress | ||
*/ | ||
'Secp256k1VerificationKey2018', | ||
/** | ||
* @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is not an ethereumAddress | ||
* @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is | ||
* not an ethereumAddress | ||
*/ | ||
'Secp256k1SignatureVerificationKey2018', | ||
/** | ||
* @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is not an ethereumAddress | ||
* @deprecated, supported for backward compatibility. Equivalent to EcdsaSecp256k1VerificationKey2019 when key is | ||
* not an ethereumAddress | ||
*/ | ||
@@ -160,10 +211,2 @@ 'EcdsaPublicKeySecp256k1', | ||
// Exporting errorCodes in a machine readable format rather than human readable format to be used in higher level module | ||
export const INVALID_JWT = 'invalid_jwt' | ||
export const INAVLID_CONFIG = 'invalid_config' | ||
export const INVALID_SIGNATURE = 'invalid_signature' | ||
export const NOT_SUPPORTED = 'not_supported' | ||
export const NO_SUITABLE_KEYS = 'no_suitable_keys' | ||
export const RESOLVE_ERROR = 'resolve_error' | ||
type LegacyVerificationMethod = { publicKey?: string } | ||
@@ -250,3 +293,4 @@ | ||
/** | ||
* Creates a signed JWT given an address which becomes the issuer, a signer, and a payload for which the signature is over. | ||
* Creates a signed JWT given an address which becomes the issuer, a signer, and a payload for which the signature is | ||
* over. | ||
* | ||
@@ -262,8 +306,9 @@ * @example | ||
* @param {String} options.issuer The DID of the issuer (signer) of JWT | ||
* @param {String} options.alg [DEPRECATED] The JWT signing algorithm to use. Supports: [ES256K, ES256K-R, Ed25519, EdDSA], Defaults to: ES256K. | ||
* Please use `header.alg` to specify the algorithm | ||
* @param {String} options.alg [DEPRECATED] The JWT signing algorithm to use. Supports: | ||
* [ES256K, ES256K-R, Ed25519, EdDSA], Defaults to: ES256K. Please use `header.alg` to specify the algorithm | ||
* @param {Signer} options.signer a `Signer` function, Please see `ES256KSigner` or `EdDSASigner` | ||
* @param {boolean} options.canonicalize optional flag to canonicalize header and payload before signing | ||
* @param {Object} header optional object to specify or customize the JWT header | ||
* @return {Promise<Object, Error>} a promise which resolves with a signed JSON Web Token or rejects with an error | ||
* @return {Promise<Object, Error>} a promise which resolves with a signed JSON Web Token or | ||
* rejects with an error | ||
*/ | ||
@@ -321,20 +366,27 @@ export async function createJWT( | ||
* Verifies given JWT. If the JWT is valid, the promise returns an object including the JWT, the payload of the JWT, | ||
* and the did doc of the issuer of the JWT. | ||
* and the DID document of the issuer of the JWT. | ||
* | ||
* @example | ||
* verifyJWT('did:uport:eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJyZXF1Z....', {audience: '5A8bRWU3F7j3REx3vkJ...', callbackUrl: 'https://...'}).then(obj => { | ||
* const did = obj.did // DID of signer | ||
* const payload = obj.payload | ||
* const doc = obj.doc // DID Document of signer | ||
* const jwt = obj.jwt | ||
* const signerKeyId = obj.signerKeyId // ID of key in DID document that signed JWT | ||
* ... | ||
* }) | ||
* ```ts | ||
* verifyJWT( | ||
* 'did:uport:eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJyZXF1Z....', | ||
* {audience: '5A8bRWU3F7j3REx3vkJ...', callbackUrl: 'https://...'} | ||
* ).then(obj => { | ||
* const did = obj.did // DID of signer | ||
* const payload = obj.payload | ||
* const doc = obj.didResolutionResult.didDocument // DID Document of issuer | ||
* const jwt = obj.jwt | ||
* const signerKeyId = obj.signer.id // ID of key in DID document that signed JWT | ||
* ... | ||
* }) | ||
* ``` | ||
* | ||
* @param {String} jwt a JSON Web Token to verify | ||
* @param {Object} [options] an unsigned credential object | ||
* @param {Boolean} options.auth Require signer to be listed in the authentication section of the DID document (for Authentication purposes) | ||
* @param {Boolean} options.auth Require signer to be listed in the authentication section of the | ||
* DID document (for Authentication purposes) | ||
* @param {String} options.audience DID of the recipient of the JWT | ||
* @param {String} options.callbackUrl callback url in JWT | ||
* @return {Promise<Object, Error>} a promise which resolves with a response object or rejects with an error | ||
* @return {Promise<Object, Error>} a promise which resolves with a response object or rejects with an | ||
* error | ||
*/ | ||
@@ -350,8 +402,3 @@ export async function verifyJWT( | ||
proofPurpose: undefined, | ||
policies: { | ||
nbf: undefined, | ||
iat: undefined, | ||
exp: undefined, | ||
now: undefined, | ||
}, | ||
policies: {}, | ||
} | ||
@@ -370,3 +417,3 @@ ): Promise<JWTVerified> { | ||
if (!payload.iss) { | ||
throw new Error('invalid_jwt: JWT iss is required') | ||
throw new Error(`${JWT_ERROR.INVALID_JWT}: JWT iss is required`) | ||
} | ||
@@ -376,3 +423,3 @@ | ||
if (!payload.sub) { | ||
throw new Error('invalid_jwt: JWT sub is required') | ||
throw new Error(`${JWT_ERROR.INVALID_JWT}: JWT sub is required`) | ||
} | ||
@@ -386,3 +433,3 @@ if (typeof payload.sub_jwk === 'undefined') { | ||
if (!payload.did) { | ||
throw new Error('invalid_jwt: JWT did is required') | ||
throw new Error(`${JWT_ERROR.INVALID_JWT}: JWT did is required`) | ||
} | ||
@@ -395,3 +442,3 @@ did = payload.did | ||
if (!did) { | ||
throw new Error(`invalid_jwt: No DID has been found in the JWT`) | ||
throw new Error(`${JWT_ERROR.INVALID_JWT}: No DID has been found in the JWT`) | ||
} | ||
@@ -406,3 +453,3 @@ | ||
const signer: VerificationMethod = await verifyJWSDecoded({ header, data, signature } as JWSDecoded, authenticators) | ||
const now: number = options.policies?.now ? options.policies.now : Math.floor(Date.now() / 1000) | ||
const now: number = typeof options.policies?.now === 'number' ? options.policies.now : Math.floor(Date.now() / 1000) | ||
const skewTime = typeof options.skewTime !== 'undefined' && options.skewTime >= 0 ? options.skewTime : NBF_SKEW | ||
@@ -413,13 +460,15 @@ if (signer) { | ||
if (payload.nbf > nowSkewed) { | ||
throw new Error(`invalid_jwt: JWT not valid before nbf: ${payload.nbf}`) | ||
throw new Error(`${JWT_ERROR.INVALID_JWT}: JWT not valid before nbf: ${payload.nbf}`) | ||
} | ||
} else if (options.policies?.iat !== false && payload.iat && payload.iat > nowSkewed) { | ||
throw new Error(`invalid_jwt: JWT not valid yet (issued in the future) iat: ${payload.iat}`) | ||
throw new Error(`${JWT_ERROR.INVALID_JWT}: JWT not valid yet (issued in the future) iat: ${payload.iat}`) | ||
} | ||
if (options.policies?.exp !== false && payload.exp && payload.exp <= now - skewTime) { | ||
throw new Error(`invalid_jwt: JWT has expired: exp: ${payload.exp} < now: ${now}`) | ||
throw new Error(`${JWT_ERROR.INVALID_JWT}: JWT has expired: exp: ${payload.exp} < now: ${now}`) | ||
} | ||
if (payload.aud) { | ||
if (options.policies?.aud !== false && payload.aud) { | ||
if (!options.audience && !options.callbackUrl) { | ||
throw new Error('invalid_config: JWT audience is required but your app address has not been configured') | ||
throw new Error( | ||
`${JWT_ERROR.INVALID_AUDIENCE}: JWT audience is required but your app address has not been configured` | ||
) | ||
} | ||
@@ -430,9 +479,9 @@ const audArray = Array.isArray(payload.aud) ? payload.aud : [payload.aud] | ||
if (typeof matchedAudience === 'undefined') { | ||
throw new Error(`invalid_config: JWT audience does not match your DID or callback url`) | ||
throw new Error(`${JWT_ERROR.INVALID_AUDIENCE}: JWT audience does not match your DID or callback url`) | ||
} | ||
} | ||
return { payload, didResolutionResult, issuer, signer, jwt } | ||
return { verified: true, payload, didResolutionResult, issuer, signer, jwt, policies: options.policies } | ||
} | ||
throw new Error( | ||
`invalid_signature: JWT not valid. issuer DID document does not contain a verificationMethod that matches the signature.` | ||
`${JWT_ERROR.INVALID_SIGNATURE}: JWT not valid. issuer DID document does not contain a verificationMethod that matches the signature.` | ||
) | ||
@@ -442,5 +491,7 @@ } | ||
/** | ||
* Resolves relevant public keys or other authenticating material used to verify signature from the DID document of provided DID | ||
* Resolves relevant public keys or other authenticating material used to verify signature from the DID document of | ||
* provided DID | ||
* | ||
* @example | ||
* ```ts | ||
* resolveAuthenticator(resolver, 'ES256K', 'did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX').then(obj => { | ||
@@ -450,9 +501,13 @@ * const payload = obj.payload | ||
* const jwt = obj.jwt | ||
* ... | ||
* // ... | ||
* }) | ||
* ``` | ||
* | ||
* @param {String} alg a JWT algorithm | ||
* @param {String} did a Decentralized IDentifier (DID) to lookup | ||
* @param {Boolean} auth Restrict public keys to ones specifically listed in the 'authentication' section of DID document | ||
* @return {Promise<DIDAuthenticator>} a promise which resolves with a response object containing an array of authenticators or if non exist rejects with an error | ||
* @param resolver - {Resolvable} a DID resolver function that can obtain the `DIDDocument` for the `issuer` | ||
* @param alg - {String} a JWT algorithm | ||
* @param issuer - {String} a Decentralized Identifier (DID) to lookup | ||
* @param proofPurpose - {ProofPurposeTypes} *Optional* Use the verificationMethod linked in that section of the | ||
* issuer DID document | ||
* @return {Promise<DIDAuthenticator>} a promise which resolves with an object containing an array of authenticators | ||
* or rejects with an error if none exist | ||
*/ | ||
@@ -467,3 +522,3 @@ export async function resolveAuthenticator( | ||
if (!types || types.length === 0) { | ||
throw new Error(`not_supported: No supported signature types for algorithm ${alg}`) | ||
throw new Error(`${JWT_ERROR.NOT_SUPPORTED}: No supported signature types for algorithm ${alg}`) | ||
} | ||
@@ -486,3 +541,5 @@ let didResult: DIDResolutionResult | ||
const { error, message } = didResult.didResolutionMetadata | ||
throw new Error(`resolver_error: Unable to resolve DID document for ${issuer}: ${error}, ${message || ''}`) | ||
throw new Error( | ||
`${JWT_ERROR.RESOLVER_ERROR}: Unable to resolve DID document for ${issuer}: ${error}, ${message || ''}` | ||
) | ||
} | ||
@@ -529,9 +586,9 @@ | ||
throw new Error( | ||
`no_suitable_keys: DID document for ${issuer} does not have public keys suitable for ${alg} with ${proofPurpose} purpose` | ||
`${JWT_ERROR.NO_SUITABLE_KEYS}: DID document for ${issuer} does not have public keys suitable for ${alg} with ${proofPurpose} purpose` | ||
) | ||
} | ||
if (!authenticators || authenticators.length === 0) { | ||
throw new Error(`no_suitable_keys: DID document for ${issuer} does not have public keys for ${alg}`) | ||
throw new Error(`${JWT_ERROR.NO_SUITABLE_KEYS}: DID document for ${issuer} does not have public keys for ${alg}`) | ||
} | ||
return { authenticators, issuer, didResolutionResult: didResult } | ||
} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
87
148
1199225
11168