UNPKG

@canva/cli

Version:

The official Canva CLI.

102 lines (84 loc) 3.06 kB
/* eslint-disable no-console */ import * as debug from "debug"; import type { Request, Response, NextFunction } from "express"; // eslint-disable-next-line @typescript-eslint/no-unused-vars import Express from "express-serve-static-core"; /** * Prefix your start command with `DEBUG=express:middleware:bearer` to enable debug logging * for this middleware */ const debugLogger = debug("express:middleware:bearer"); /** * Augment the Express request context to include the appId/userId/brandId fields decoded * from the JWT. */ declare module "express-serve-static-core" { export interface Request { user_id: string; } } const sendUnauthorizedResponse = (res: Response, message?: string) => res.status(401).json({ error: "unauthorized", message }); /** * An Express.js middleware verifying a Bearer token. * This middleware extracts the token from the `Authorization` header. * * @param getTokenFromRequest - A function that extracts a token from the request. If a token isn't found, throw a `JWTAuthorizationError`. * @returns An Express.js middleware for verifying and decoding JWTs. */ export function createBearerMiddleware( tokenToUser: (access_token: string) => Promise<string | undefined>, getTokenFromRequest: GetTokenFromRequest = getTokenFromHttpHeader, ): (req: Request, res: Response, next: NextFunction) => void { return async (req, res, next) => { try { debugLogger(`processing token for '${req.url}'`); const token = await getTokenFromRequest(req); const user = await tokenToUser(token); if (!user) { throw new AuthorizationError("Token is invalid"); } req.user_id = user; next(); } catch (e) { if (e instanceof AuthorizationError) { return sendUnauthorizedResponse(res, e.message); } next(e); } }; } export type GetTokenFromRequest = (req: Request) => Promise<string> | string; export const getTokenFromHttpHeader: GetTokenFromRequest = ( req: Request, ): string => { // The names of a HTTP header bearing the JWT, and a scheme const headerName = "Authorization"; const schemeName = "Bearer"; const header = req.header(headerName); if (!header) { throw new AuthorizationError(`Missing the "${headerName}" header`); } if (!header.match(new RegExp(`^${schemeName}\\s+[^\\s]+$`, "i"))) { console.trace( `jwtMiddleware: failed to match token in "${headerName}" header`, ); throw new AuthorizationError( `Missing a "${schemeName}" token in the "${headerName}" header`, ); } const token = header.replace(new RegExp(`^${schemeName}\\s+`, "i"), ""); return token; }; /** * A class representing JWT validation errors in the JWT middleware. * The error message provided to the constructor will be forwarded to the * API consumer trying to access a JWT-protected endpoint. * @private */ export class AuthorizationError extends Error { constructor(message: string) { super(message); Object.setPrototypeOf(this, AuthorizationError.prototype); } }