From 29fc91d6d1f743c2dfd1c23c24a866b4a099dce7 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 15 Mar 2023 17:26:21 +0000 Subject: [PATCH 1/2] Making it obvious that API key is invalid - error otherwise is quite cryptic. --- .../src/middleware/authenticated.ts | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/packages/backend-core/src/middleware/authenticated.ts b/packages/backend-core/src/middleware/authenticated.ts index 5e546b4c1c..1b6ece2c37 100644 --- a/packages/backend-core/src/middleware/authenticated.ts +++ b/packages/backend-core/src/middleware/authenticated.ts @@ -48,22 +48,31 @@ async function checkApiKey(apiKey: string, populateUser?: Function) { const decrypted = decrypt(apiKey) const tenantId = decrypted.split(SEPARATOR)[0] return doInTenant(tenantId, async () => { - const db = getGlobalDB() - // api key is encrypted in the database - const userId = (await queryGlobalView( - ViewName.BY_API_KEY, - { - key: apiKey, - }, - db - )) as string + let userId + try { + const db = getGlobalDB() + // api key is encrypted in the database + userId = (await queryGlobalView( + ViewName.BY_API_KEY, + { + key: apiKey, + }, + db + )) as string + } catch (err) { + userId = undefined + } if (userId) { return { valid: true, user: await getUser(userId, tenantId, populateUser), } } else { - throw "Invalid API key" + throw { + message: + "Invalid API key - may need re-generated, or user doesn't exist", + name: "InvalidApiKey", + } } }) } @@ -164,8 +173,10 @@ export default function ( console.error(`Auth Error: ${err.message}`) console.error(err) // invalid token, clear the cookie - if (err && err.name === "JsonWebTokenError") { + if (err?.name === "JsonWebTokenError") { clearCookie(ctx, Cookie.Auth) + } else if (err?.name === "InvalidApiKey") { + ctx.throw(403, err.message) } // allow configuring for public access if ((opts && opts.publicAllowed) || publicEndpoint) { From 39bfbdfac17dddf913b60011c63cfc8ffffe07a8 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 16 Mar 2023 16:49:31 +0000 Subject: [PATCH 2/2] PR comments. --- packages/backend-core/src/errors/errors.ts | 12 ++++++++++++ .../backend-core/src/middleware/authenticated.ts | 9 +++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/backend-core/src/errors/errors.ts b/packages/backend-core/src/errors/errors.ts index cc2e49ce98..54ca8456ab 100644 --- a/packages/backend-core/src/errors/errors.ts +++ b/packages/backend-core/src/errors/errors.ts @@ -16,6 +16,7 @@ export abstract class BudibaseError extends Error { export enum ErrorCode { USAGE_LIMIT_EXCEEDED = "usage_limit_exceeded", FEATURE_DISABLED = "feature_disabled", + INVALID_API_KEY = "invalid_api_key", HTTP = "http", } @@ -85,3 +86,14 @@ export class FeatureDisabledError extends HTTPError { } } } + +// AUTH + +export class InvalidAPIKeyError extends BudibaseError { + constructor() { + super( + "Invalid API key - may need re-generated, or user doesn't exist", + ErrorCode.INVALID_API_KEY + ) + } +} diff --git a/packages/backend-core/src/middleware/authenticated.ts b/packages/backend-core/src/middleware/authenticated.ts index 1b6ece2c37..8a97319586 100644 --- a/packages/backend-core/src/middleware/authenticated.ts +++ b/packages/backend-core/src/middleware/authenticated.ts @@ -14,6 +14,7 @@ import { decrypt } from "../security/encryption" import * as identity from "../context/identity" import env from "../environment" import { Ctx, EndpointMatcher } from "@budibase/types" +import { InvalidAPIKeyError, ErrorCode } from "../errors" const ONE_MINUTE = env.SESSION_UPDATE_PERIOD ? parseInt(env.SESSION_UPDATE_PERIOD) @@ -68,11 +69,7 @@ async function checkApiKey(apiKey: string, populateUser?: Function) { user: await getUser(userId, tenantId, populateUser), } } else { - throw { - message: - "Invalid API key - may need re-generated, or user doesn't exist", - name: "InvalidApiKey", - } + throw new InvalidAPIKeyError() } }) } @@ -175,7 +172,7 @@ export default function ( // invalid token, clear the cookie if (err?.name === "JsonWebTokenError") { clearCookie(ctx, Cookie.Auth) - } else if (err?.name === "InvalidApiKey") { + } else if (err?.code === ErrorCode.INVALID_API_KEY) { ctx.throw(403, err.message) } // allow configuring for public access