import * as jose from 'jose'; import {ConfigInterface} from '../base-types'; import * as ShopifyErrors from '../error'; import {getHMACKey} from '../utils/get-hmac-key'; import {JwtPayload} from './types'; const JWT_PERMITTED_CLOCK_TOLERANCE = 10; export interface DecodeSessionTokenOptions { checkAudience?: boolean; } export function decodeSessionToken(config: ConfigInterface) { return async ( token: string, {checkAudience = true}: DecodeSessionTokenOptions = {}, ): Promise => { let payload: JwtPayload; try { payload = ( await jose.jwtVerify(token, getHMACKey(config.apiSecretKey), { algorithms: ['HS256'], clockTolerance: JWT_PERMITTED_CLOCK_TOLERANCE, }) ).payload as unknown as JwtPayload; } catch (error) { throw new ShopifyErrors.InvalidJwtError( `Failed to parse session token '${token}': ${error.message}`, ); } // The exp and nbf fields are validated by the JWT library if (checkAudience && payload.aud !== config.apiKey) { throw new ShopifyErrors.InvalidJwtError( 'Session token had invalid API key', ); } return payload; }; }