From 8ed4eb3899b89032acd13095b6c72e2676ff4eaa Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Mon, 28 Oct 2024 13:34:51 +0330 Subject: [PATCH] feat(pre-handlers): Add requireAccessToken middleware This commit adds a new file, require-access-token.ts, which contains a middleware function for Nanotron API requests. The function checks the authorization header for a Bearer token and compares it to the provided access token. If the token is missing or invalid, it sends an appropriate error response and prevents further handlers from executing. Example usage: nanotronApiServer.defineRoute({ method: 'POST', url: 'secure-endpoint', preHandlers: [requireAccessToken('mySecretToken')], async handler() { this.serverResponse.replyJson({ ok: true, message: 'Access granted!', }); }, }); --- .../src/handler/require-access-token.ts | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 packages/pre-handlers/src/handler/require-access-token.ts diff --git a/packages/pre-handlers/src/handler/require-access-token.ts b/packages/pre-handlers/src/handler/require-access-token.ts new file mode 100644 index 0000000..59f0b12 --- /dev/null +++ b/packages/pre-handlers/src/handler/require-access-token.ts @@ -0,0 +1,53 @@ +import {HttpStatusCodes, type NanotronClientRequest} from '@alwatr/nanotron-api-server'; + +import {getAuthBearer} from '../lib/get-auth-bearer.js'; + +/** + * Middleware to require a valid access token for a Nanotron API request. + * + * This function checks the authorization header for a Bearer token and compares it to the provided access token. + * If the token is missing or invalid, it sends an appropriate error response and prevents further handlers from executing. + * + * @param {string} accessToken - The valid access token to compare against. + * @returns {Function} A middleware function for Nanotron API requests. + * + * @example + * ```ts + * nanotronApiServer.defineRoute({ + * method: 'POST', + * url: 'secure-endpoint', + * preHandlers: [requireAccessToken('mySecretToken')], + * async handler() { + * this.serverResponse.replyJson({ + * ok: true, + * message: 'Access granted!', + * }); + * }, + * }); + * ``` + */ +export const requireAccessToken = (accessToken: string) => + async function requireAccessToken_(this: NanotronClientRequest): Promise { + const userToken = getAuthBearer(this.headers.authorization); + this.logger_.logMethodArgs?.('requireAccessToken', {userToken}); + + if (userToken === null) { + this.serverResponse.statusCode = HttpStatusCodes.Error_Client_401_Unauthorized; + this.serverResponse.replyErrorResponse({ + ok: false, + errorCode: 'authorization_required', + errorMessage: 'Authorization token required', + }); + return; + } + + if (userToken !== accessToken) { + this.serverResponse.statusCode = HttpStatusCodes.Error_Client_403_Forbidden; + this.serverResponse.replyErrorResponse({ + ok: false, + errorCode: 'access_denied', + errorMessage: 'Access denied, token is invalid!', + }); + } + }; +