ez-jwt
JSON Web Token (JWT) and JSON Web Signature (JWS) validation using WEB Cryptography API.
Features
- Validates JWT/JWS signature, returns JWT claims
-
jwtValidate(jwt)
returns JWT claims -
jwsValidate(jws)
returns JWS (JOSE) header and JWS payload
-
- Accepts JWS Compact Serialization format for JWT/JWS
- Uses Web Cryptography API to
- import keys encoded in the JSON key format (JWK)
- validate messages using digital signatures or MACs (JWS)
- Understands all standard algorithms for digital signatures and MACs (according to RFC 7518). Particular algorithm support depends on a browser.
- Сompliant with Javascript Object Signing and Encryption (JOSE) RFCs
- Tiny package
- ES6 module, typings available
Install
npm i ez-jwt
Usage
The main function to validate a JWT and obtain the JWT claims is jwtValidate()
. Let's use RFC 7515 example JWT.
// JWS header is { typ: 'JWT', alg: 'HS256' }
// JWT claims is { iss: 'joe', exp: 1300819380, 'http://example.com/is_root': true }
const token =
'eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJle' +
'HAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnV' +
'lfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk';
This token has no information about the key to validate it, so we need to provide the key explicitly. The public key to validate the token is present in the same example.
const jwk = {
kty: 'oct',
k: 'AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow'
};
Use jwtValidate()
and provide the key to validate the token, get JWT claims.
import { jwtValidate } from 'ez-jwt';
jwtValidate(token, {keys: jwk})
.then((claims) => {
// JWT is valid
// claims value is { iss: 'joe', exp: 1300819380, 'http://example.com/is_root': true }
});
We don't need to provide any keys if a token JWS header has information about the key to validate it. See Key providers.
JWT/JWS validation
Input JWT/JWS should be in JWS Compact Serialization format: a string of three BASE64URL-encoded parts (header, payload, and signature), separated by .
symbols.
Any digitally signed JWT is a JWS with a well-defined payload, which is JWT Claims.
Compact Serialization Format | BASE64URL(JSON( x )) |
. |
BASE64URL( x ) |
. |
BASE64URL( x ) |
---|---|---|---|---|---|
JWS | JWS Header |
ArrayBuffer |
JWS Signature |
||
JWT | JWS Header |
JSON(JWT Claims) |
JWS Signature |
JWT validation process performed by jwtValidate()
:
- Validate JWT as JWS using
jwsValidate()
.- Split the input JWS into three parts: header, payload, signature.
-
BASE64URL_DECODE()
all the parts. - UTF-8 decode and JSON parse the header, get JWS header.
- Check JWS header parameter
crit
(should be undefined). - Check JWS header parameter
alg
(should be one of the standard algorithms). - Apply the key provider function to the header and get an array of keys.
- Filter key array by key ID, algorithm, usage, and operations.
- Use the remaining key(s) to verify JWS signature.
- Return JWS header and payload.
- Check JWS header parameters
typ
(should be undefined or equals'JWT'
) andcty
(should be undefined). - UTF-8 decode and JSON parse JWS payload, get JWT claims object.
- Validate JWT claims
exp
andnbf
(if present). - Return JWT claims.
Keys providers
To validate a JWS Signature the correct public key is required. The key should be provided to jwsValidate()
function. A token issuer can provide the public key to validate the token in several ways and different formats.
JWK/JWKS public key
This is the main format of key data supported by the package.
- A JWK is provided in JWS header (parameter
jwk
). - One or more JWK is known to the application.
- URI of JWKS endpoint is provided in JWS header (parameter
jku
). - URI of JWKS endpoint is known to the application (for example
.well-known/jwks.json
for OAuth2 applications).
The default key provider jwsHeaderKeysProvider()
gets jwk
parameter key and adds all the keys from JWKS endpoint defined by jku
parameter. One can add some more application keys by passing them as an argument for jwsHeaderKeysProvider(appKeys)
. appKeys
value can be JWK
, JWK[]
, or JWKS
object.
Two application keys providers jwkAppKeysProvider()
and jwkAppUriProvider()
ignore JWS header parameters and provide application keys only.
One can design a custom key provider function and pass it to jwsValidate()
.
Key provider is a function that takes JWS header and returns keys to validate the JWS.
type JwsKeyProvider = (h: JWSHeader) => Promise<JWK[]>;
Key provider functions summary:
Key provider | JWS header jkw
|
JWS header jku
|
Application JWK/JWK[]/JWKS | Application JWKS endpoint |
---|---|---|---|---|
jwsHeaderKeysProvider() |
+ | + | ||
jwsHeaderKeysProvider(appKeys) |
+ | + | appKeys |
|
jwkAppKeysProvider(appKeys) |
appKeys |
|||
jwkAppUriProvider(jwks_uri) |
jwks_uri |
Note: one can download all the keys from JWKS endpoint to appKeys
variable in advance and use jwkAppKeysProvider(appKeys)
(or jwsHeaderKeysProvider(appKeys)
) provider instead of jwkAppUriProvider()
.
JWKS endpoint
A token issuer JWKS endpoint returns all the public keys the issuer uses to sign tokens. One can filter the keys by kid
or try to use all the keys. For example, Google's OpenID Connect services JWKS endpoint returns the following two keys:
{
"keys": [
{
"kid": "0a7dc12664590c957ffaebf7b6718297b864ba91",
"use": "sig",
"kty": "RSA",
"alg": "RS256",
"e": "AQAB",
"n": "7NfiTQcshWgrEdKbHC2e..............eNVz39274ippJSQ"
},
{
"kid": "bc49530e1ff9083dd5eeaa06be2ce437f49c905e",
"use": "sig",
"kty": "RSA",
"alg": "RS256",
"e": "AQAB",
"n": "xPXUFDnAQQ5daLQTcQsV..............Na3BbnAhj7miR0w"
}
]
}
X.509 certificate public key
Public key data can be provided X.509 certificate as a SubjectPublicKeyInfo
object. JWS header parameters x5u
, x5c
, x5t
, x5t#S256
provide key data in form of an X.509 certificate.
Web Cryptography API doesn't support X.509 certificate processing so the package doesn't support those keys data. One can create a custom key provider function and use a third-party library to parse X.509 cert and convert key data to JWK format.