UNPKG

@auth0/auth0-spa-js

Version:

Auth0 SDK for Single Page Applications using Authorization Code Grant Flow with PKCE

90 lines (84 loc) 2 kB
import { urlDecodeB64 } from './utils'; const idTokendecoded = [ 'iss', 'aud', 'exp', 'nbf', 'iat', 'jti', 'azp', 'nonce', 'auth_time', 'at_hash', 'c_hash', 'acr', 'amr', 'sub_jwk', 'cnf', 'sip_from_tag', 'sip_date', 'sip_callid', 'sip_cseq_num', 'sip_via_branch', 'orig', 'dest', 'mky', 'events', 'toe', 'txn', 'rph', 'sid', 'vot', 'vtm' ]; export const decode = (token: string) => { const [header, payload, signature] = token.split('.'); const payloadJSON = JSON.parse(urlDecodeB64(payload)); const claims: IdToken = {}; const user = {}; Object.keys(payloadJSON).forEach(k => { claims[k] = payloadJSON[k]; if (!idTokendecoded.includes(k)) { user[k] = payloadJSON[k]; } }); return { encoded: { header, payload, signature }, header: JSON.parse(urlDecodeB64(header)), claims, user }; }; export const verify = (options: JWTVerifyOptions) => { const decoded = decode(options.id_token); if (decoded.claims.iss !== options.iss) { throw new Error('Invalid issuer'); } if (decoded.claims.aud !== options.aud) { throw new Error('Invalid audience'); } if (decoded.header.alg !== 'RS256') { throw new Error('Invalid algorithm'); } if (decoded.claims.nonce !== options.nonce) { throw new Error('Invalid nonce'); } const now = new Date(); const expDate = new Date(0); const iatDate = new Date(0); const nbfDate = new Date(0); const leeway = options.leeway || 60; expDate.setUTCSeconds(decoded.claims.exp + leeway); iatDate.setUTCSeconds(decoded.claims.iat - leeway); nbfDate.setUTCSeconds(decoded.claims.nbf - leeway); if (now > expDate) { throw new Error('id_token expired'); } if (now < iatDate) { throw new Error('id_token was issued in the future (invalid iat)'); } if (typeof decoded.claims.nbf !== 'undefined' && now < nbfDate) { throw new Error('token is not yet valid (invalid notBefore)'); } return decoded; };