UNPKG

hono

Version:

Web framework built on Web Standards

83 lines (82 loc) 2.9 kB
// src/middleware/bearer-auth/index.ts import { HTTPException } from "../../http-exception.js"; import { timingSafeEqual } from "../../utils/buffer.js"; var TOKEN_STRINGS = "[A-Za-z0-9._~+/-]+=*"; var PREFIX = "Bearer"; var HEADER = "Authorization"; var bearerAuth = (options) => { if (!("token" in options || "verifyToken" in options)) { throw new Error('bearer auth middleware requires options for "token"'); } if (!options.realm) { options.realm = ""; } if (options.prefix === void 0) { options.prefix = PREFIX; } const realm = options.realm?.replace(/"/g, '\\"'); const prefixRegexStr = options.prefix === "" ? "" : `${options.prefix} +`; const regexp = new RegExp(`^${prefixRegexStr}(${TOKEN_STRINGS}) *$`); const wwwAuthenticatePrefix = options.prefix === "" ? "" : `${options.prefix} `; const throwHTTPException = async (c, status, wwwAuthenticateHeader, messageOption) => { const headers = { "WWW-Authenticate": wwwAuthenticateHeader }; const responseMessage = typeof messageOption === "function" ? await messageOption(c) : messageOption; const res = typeof responseMessage === "string" ? new Response(responseMessage, { status, headers }) : new Response(JSON.stringify(responseMessage), { status, headers: { ...headers, "content-type": "application/json; charset=UTF-8" } }); throw new HTTPException(status, { res }); }; return async function bearerAuth2(c, next) { const headerToken = c.req.header(options.headerName || HEADER); if (!headerToken) { await throwHTTPException( c, 401, `${wwwAuthenticatePrefix}realm="${realm}"`, options.noAuthenticationHeaderMessage || "Unauthorized" ); } else { const match = regexp.exec(headerToken); if (!match) { await throwHTTPException( c, 400, `${wwwAuthenticatePrefix}error="invalid_request"`, options.invalidAuthenticationHeaderMessage || "Bad Request" ); } else { let equal = false; if ("verifyToken" in options) { equal = await options.verifyToken(match[1], c); } else if (typeof options.token === "string") { equal = await timingSafeEqual(options.token, match[1], options.hashFunction); } else if (Array.isArray(options.token) && options.token.length > 0) { for (const token of options.token) { if (await timingSafeEqual(token, match[1], options.hashFunction)) { equal = true; break; } } } if (!equal) { await throwHTTPException( c, 401, `${wwwAuthenticatePrefix}error="invalid_token"`, options.invalidTokenMessage || "Unauthorized" ); } } } await next(); }; }; export { bearerAuth };