Skip to main content

Auth Enrich Hook

Use auth.handlers.hooks.enrich to inject request-scoped data into auth.meta before access checks run.

This is the right place for data such as:

  • workspace membership
  • organization role
  • feature flags
  • request-scoped tenancy metadata

Configuration

import { defineConfig } from '@edgebase/shared';

export default defineConfig({
auth: {
handlers: {
hooks: {
enrich: async (auth, request) => {
const workspaceRole = await lookupWorkspaceRole(auth.id);
return {
workspaceRole,
requestPath: new URL(request.url).pathname,
};
},
},
},
},

databases: {
workspace: {
access: {
access(auth) {
return auth?.meta?.workspaceRole === 'member'
|| auth?.meta?.workspaceRole === 'admin';
},
},
tables: {
docs: {
access: {
read(auth) {
return auth?.meta?.workspaceRole !== undefined;
},
insert(auth) {
return auth?.meta?.workspaceRole === 'admin';
},
},
},
},
},
},
});

Execution Order

Request -> JWT verification -> auth.handlers.hooks.enrich() -> auth.meta merge -> access evaluation

Signature

type AuthEnrichHook = (
auth: AuthContext,
request: Request,
) => Promise<Record<string, unknown>> | Record<string, unknown>;

Behavior

  • Runs only for authenticated requests.
  • Timeout is 50ms.
  • On error or timeout, auth.meta becomes {}.
  • Access logic should treat missing meta as deny-by-default.

Where auth.meta is available

  • database/table access
  • storage bucket access
  • realtime namespace access
  • room access

Example: Rooms

export default defineConfig({
auth: {
handlers: {
hooks: {
enrich: async (auth) => ({
workspaceId: await lookupWorkspace(auth.id),
}),
},
},
},
rooms: {
board: {
access: {
join(auth) {
return Boolean(auth?.meta?.workspaceId);
},
},
},
},
});

See Also