# API Reference Complete reference for every export, organized by entry point. --- ## @supabase/server ### withSupabase ```ts function withSupabase( config: WithSupabaseConfig, handler: (req: Request, ctx: SupabaseContext) => Promise, ): (req: Request) => Promise ``` Wraps a fetch handler with auth, CORS, and client creation. Returns a `(req: Request) => Promise` function suitable for `export default { fetch }`. - Handles `OPTIONS` preflight when CORS is enabled - Verifies credentials per `config.auth` - Returns JSON error response on auth failure - Adds CORS headers to all responses - Buffers the request body at the entry point, so composed middleware and the handler can each read it - Reading the raw `req.body` stream bypasses the buffer, so a handler that forwards the request with `fetch()` after another layer has read the body rebuilds it from `await req.arrayBuffer()`. ```ts function withSupabase( config: WithSupabaseConfig, ): Entry> ``` Called with config only, `withSupabase` is an entry for `pipeline` from `@supabase/middleware`. Position decides what runs before and after the auth gate. A config carrying a `middleware` key is refused when the stack is built; entries compose through `pipeline` or nesting: ```ts import { pipeline } from '@supabase/middleware' import { withOAuthProtectedResource, withSupabase } from '@supabase/server' import { withPostgresClient } from '@supabase/server/middleware/postgres' pipeline( [ withOAuthProtectedResource(), withSupabase({ auth: 'user' }), withPostgresClient(), ], handler, ) ``` Entries before `withSupabase` see every request, including unauthenticated ones, and observe its `401` responses on the way out. Entries after it receive the full `SupabaseContext` and may declare prerequisites on its keys; an entry contributing one of those keys is a compile-time conflict. Nesting works the same way: `withOAuthProtectedResource(withSupabase(config, handler))` places the OAuth middleware ahead of the gate, `withSupabase(config, withPostgresClient(handler))` places Postgres behind it. Placing `withOAuthProtectedResource` directly after `withSupabase` with an auth mode that requires credentials is refused when the stack is built; a pre-auth middleware separated from `withSupabase` by another entry is not detected and must be ordered by hand. > **Alpha.** The entry form and the `@supabase/server/middleware/*` subpaths > track `@supabase/middleware` 0.x — entry shapes and context keys may change > between 0.x releases. Everything else in `@supabase/server` is stable. ### createSupabaseContext ```ts function createSupabaseContext( request: Request, options?: WithSupabaseConfig, ): Promise< | { data: SupabaseContext; error: null } | { data: null; error: AuthError } > ``` Creates a `SupabaseContext` from a request. Returns a result tuple. The `cors` option is ignored. Defaults to `auth: 'user'` when `options` is omitted. --- ## @supabase/server/core ### verifyAuth ```ts function verifyAuth( request: Request, options: { auth?: AuthModeWithKey | AuthModeWithKey[] env?: Partial }, ): Promise<{ data: AuthResult; error: null } | { data: null; error: AuthError }> ``` Extracts credentials from a request and verifies them. Convenience wrapper over `extractCredentials` + `verifyCredentials`. ### verifyCredentials ```ts function verifyCredentials( credentials: Credentials, options: { auth?: AuthModeWithKey | AuthModeWithKey[] env?: Partial }, ): Promise<{ data: AuthResult; error: null } | { data: null; error: AuthError }> ``` Verifies pre-extracted credentials against allowed auth modes. Tries each mode in order — first match wins. ### extractCredentials ```ts function extractCredentials(request: Request): Credentials ``` Reads `Authorization: Bearer ` and `apikey` headers from a request. Pure extraction, no validation. Synchronous. ### resolveEnv ```ts function resolveEnv( overrides?: Partial, ): { data: SupabaseEnv; error: null } | { data: null; error: EnvError } ``` Resolves Supabase environment configuration from runtime variables. `SUPABASE_URL` is the only hard requirement. ### createContextClient ```ts function createContextClient( options?: CreateContextClientOptions, ): SupabaseClient ``` Creates a user-scoped Supabase client. RLS applies. **Throws `EnvError`** if URL or publishable key is missing. Configured with: - Publishable key (named or default) as `apikey` header - User's JWT as `Authorization: Bearer` header (when `auth.token` is provided) - `persistSession: false`, `autoRefreshToken: false`, `detectSessionInUrl: false` ### createAdminClient ```ts function createAdminClient( options?: CreateAdminClientOptions, ): SupabaseClient ``` Creates an admin Supabase client that bypasses RLS. **Throws `EnvError`** if URL or secret key is missing. --- ## @supabase/server/adapters/hono ### withSupabase (Hono) ```ts function withSupabase( config?: Omit, ): MiddlewareHandler ``` Hono middleware. Sets `c.var.supabaseContext` on the Hono context. Throws `HTTPException` on auth failure with `cause: AuthError`. Skips if `c.var.supabaseContext` is already set (enables route-level overrides). Defaults to `auth: 'user'` when config is omitted. --- ## @supabase/server/adapters/h3 ### withSupabase (H3) ```ts function withSupabase(config?: Omit): Middleware ``` H3 middleware. Sets `event.context.supabaseContext` on the H3 event. Throws `HTTPError` on auth failure with `cause: AuthError`. Skips if `event.context.supabaseContext` is already set (enables chained middleware). Defaults to `auth: 'user'` when config is omitted. --- ## @supabase/server/adapters/elysia ### withSupabase (Elysia) ```ts function withSupabase(config?: Omit): Elysia ``` Elysia plugin that resolves `supabaseContext` into the request context. Throws an error on auth failure with `cause: AuthError`. Skips if `supabaseContext` is already resolved by a prior plugin. Defaults to `auth: 'user'` when config is omitted. --- ## @supabase/server/middleware/claims > **Alpha.** Composing `withSupabase` as a `pipeline` entry and the > `@supabase/server/middleware/*` subpaths track `@supabase/middleware` 0.x — > entry shapes and context keys may change between 0.x releases. The > `withSupabase(config, handler)` form is stable. ### withClaims ```ts const withClaims: Middleware< 'jwtClaims', WithClaimsConfig | void, Record, JWTClaims | null > ``` Contributes `ctx.jwtClaims` by verifying the caller's Bearer token against the project JWKS. This is the same verification core `withSupabase` uses for its `user` auth mode. Behavior: - No `Authorization: Bearer` token, or an `sb_*` API key in that position: contributes `null` and the request proceeds as anonymous. - Token present but invalid: short-circuits with a 401 and code `INVALID_JWT`, naming the specific reason (expired, bad signature, unknown `kid`, malformed, no `sub`). - Token present but no JWKS configured: short-circuits with a 500 and code `JWKS_NOT_CONFIGURED` — the same code `withSupabase`'s `user` mode reports, with a `hint` naming this middleware's `jwks` option. Verification is required; the middleware has no decode-only mode. - Remote JWKS unreachable: short-circuits with a 500 and code `JWKS_FETCH_FAILED`. Responses use the standard [error payload](error-handling.md#what-a-failure-looks-like). `withClaims` is not an auth gate. It never rejects a request that has no token, so `[withClaims(), withSupabaseClient()]` is not the composable form of `withSupabase({ auth: 'user' })` and accepts anonymous callers. To require an authenticated caller, compose `withRequiredClaims` (`@supabase/server/middleware/required-claims`) instead. The two entries share the `jwtClaims` key, so a pipeline picks "claims if present" or "claims required"; composing both is a compile-time conflict. ### WithClaimsConfig ```ts interface WithClaimsConfig { jwks?: JSONWebKeySet | URL } ``` Defaults to `SUPABASE_JWKS` (inline JSON) or `SUPABASE_JWKS_URL` (https endpoint) from the environment. --- ## @supabase/server/middleware/required-claims > **Alpha.** Composing `withSupabase` as a `pipeline` entry and the > `@supabase/server/middleware/*` subpaths track `@supabase/middleware` 0.x — > entry shapes and context keys may change between 0.x releases. The > `withSupabase(config, handler)` form is stable. ### withRequiredClaims ```ts const withRequiredClaims: Middleware< 'jwtClaims', WithRequiredClaimsConfig | void, Record, JWTClaims > ``` The user-mode auth gate. Verifies the caller's Bearer token against the project JWKS and contributes **non-null** `ctx.jwtClaims`. This is the same verification core `withSupabase` uses for its `user` auth mode. Behavior: - No `Authorization` header: short-circuits with a 401 and code `MISSING_CREDENTIALS`. The handler never runs. - An `sb_*` API key in the `Authorization` header: a 401 with code `UNUSABLE_CREDENTIAL` — a credential arrived, just not a user JWT. - Token present but invalid: a 401 with code `INVALID_JWT`, naming the specific reason. - Token present but no JWKS configured: short-circuits with a 500 and code `JWKS_NOT_CONFIGURED` — the same code `withSupabase`'s `user` mode reports, with a `hint` naming this middleware's `jwks` option. Verification is required; the middleware has no decode-only mode. - Remote JWKS unreachable: short-circuits with a 500 and code `JWKS_FETCH_FAILED`. Responses use the standard [error payload](error-handling.md#what-a-failure-looks-like). `withRequiredClaims` is the required-caller counterpart to `withClaims`: "claims required" rather than "claims if present". The two share the `jwtClaims` key, so composing both in one pipeline is a compile-time conflict. Because the contribution is non-null, gated handlers read `ctx.jwtClaims` directly, and entries declaring a `jwtClaims` prerequisite, such as `withPostgresClient`, compose with no further verification: ```ts pipeline([withRequiredClaims(), withPostgresClient()], async (req, ctx) => { const rows = await ctx.postgres.query`select id, title from posts` return Response.json({ rows, caller: ctx.jwtClaims.sub }) }) ``` The gate's 401 and 500 short-circuits carry no CORS headers, and a bare pipeline answers no `OPTIONS` preflight. For browser callers, compose `withCors` (`@supabase/middleware/cors`) ahead of the gate: it answers preflight before the gate runs and stamps `Access-Control-*` headers on the gate's short-circuit responses. After `withSupabase` in a `pipeline` the context already carries verified `jwtClaims`, so placing the gate there is a compile-time conflict. Use `withSupabase({ auth: 'user' })` to gate that path. The gate contributes `jwtClaims` and nothing else. A handler that needs the full `SupabaseContext` behind an auth gate (for example `ctx.userClaims` or `ctx.authMode`, which no composable entry contributes) uses `withSupabase({ auth: 'user' })` directly. A host that takes an entries array can wrap it as the sole entry. `cors: 'disabled'` leaves CORS handling to the host: ```ts const entry = (h: (req: Request, ctx: object) => Promise) => withSupabase({ auth: 'user', cors: 'disabled' }, h) ``` ### WithRequiredClaimsConfig ```ts interface WithRequiredClaimsConfig { jwks?: JSONWebKeySet | URL } ``` Defaults to `SUPABASE_JWKS` (inline JSON) or `SUPABASE_JWKS_URL` (https endpoint) from the environment. --- ## @supabase/server/middleware/postgres > **Alpha.** Composing `withSupabase` as a `pipeline` entry and the > `@supabase/server/middleware/*` subpaths track `@supabase/middleware` 0.x — > entry shapes and context keys may change between 0.x releases. The > `withSupabase(config, handler)` form is stable. ### withPostgresClient ```ts const withPostgresClient: Middleware< 'postgres', WithPostgresClientConfig | void, { jwtClaims: RequestClaims | null }, PostgresApi > ``` Contributes `ctx.postgres` — a `pg` client scoped to the caller by RLS. Each query runs in its own transaction that sets `request.jwt.claims` and drops to the caller's role before the statement, so `auth.uid()` resolves and policies enforce. Only `authenticated` and `anon` are assumed. A verified token naming any other role — `service_role` or a custom role — short-circuits with a 500 and `{ message, code: 'UNSUPPORTED_ROLE' }` naming the role, rather than being downgraded to `anon`. A missing or absent `role` claim is `anon`. Requires `ctx.jwtClaims` upstream — supplied by `withSupabase` or by `withClaims` in a standalone `pipeline`. Composing it without one is a compile-time error. Short-circuits with a 500 and code `MISSING_CONNECTION_STRING` when no connection string is available. Needs raw TCP: Node, Deno, Bun, and the Supabase Edge runtime, not Workers-style isolates. `pg` is an optional peer dependency. See [`docs/postgres.md`](postgres.md). ### PostgresApi ```ts interface PostgresApi { query>( strings: TemplateStringsArray, ...values: unknown[] ): Promise queryRaw>( text: string, params?: unknown[], ): Promise } ``` The value at `ctx.postgres`. Both methods return the result rows directly (not a `pg` `Result`). `query` is a **tagged template**, so every interpolation becomes a bind parameter and can never alter the statement: ```ts const rows = await ctx.postgres .query`select id, body from notes where id = ${id}` // -> select id, body from notes where id = $1 with values [id] ``` Tagged templates cannot carry type arguments, so annotate the binding instead of writing `query`: ```ts const rows: NoteRow[] = await ctx.postgres.query`select id, body from notes` ``` Passing a plain string to `query` throws — the two calls differ only in their brackets, so it refuses rather than silently reinterpreting. `queryRaw` takes SQL text plus `params`, for text that cannot be a literal: a query builder emitting `{ sql, parameters }`, or SQL that must interpolate an identifier. Identifiers can never be bind parameters, so check them against a set you control and quote them with `ident`: ```ts import { ident } from '@supabase/server/middleware/postgres' const SORTABLE = new Set(['created_at', 'title']) if (!SORTABLE.has(column)) throw new Error('unsupported sort column') const rows = await ctx.postgres.queryRaw( `select id, title from posts order by ${ident(column)} desc`, ) ``` `ident` quotes and escapes, but does not authorize — it stops injection, not a caller reading a column they should not see. The allowlist is what does that. ### WithPostgresClientConfig ```ts interface WithPostgresClientConfig { connectionString?: string } ``` Defaults to the `SUPABASE_DB_URL` environment variable. Pools are created lazily, one per connection string per process. ### RequestClaims ```ts interface RequestClaims { role?: string [key: string]: unknown } ``` The minimal claims shape `withPostgresClient` requires upstream at `ctx.jwtClaims`. Satisfied by `withSupabase`'s JWKS-verified claims and by `withClaims`. Only `role` is read; the whole object is serialized into `request.jwt.claims`. --- ## @supabase/server/middleware/postgres-admin > **Alpha.** Composing `withSupabase` as a `pipeline` entry and the > `@supabase/server/middleware/*` subpaths track `@supabase/middleware` 0.x — > entry shapes and context keys may change between 0.x releases. The > `withSupabase(config, handler)` form is stable. ### withPostgresAdminClient ```ts const withPostgresAdminClient: Middleware< 'postgresAdmin', WithPostgresAdminClientConfig | void, Record, PostgresApi > ``` Contributes `ctx.postgresAdmin` — a `pg` client that **bypasses RLS**. Queries run as-is, as the role in the connection string: no claim injection, no role switching, no wrapping transaction. Declares no upstream prerequisite, so it composes in any auth mode including `'secret'` and `'none'`. Shares the pool cache with `withPostgresClient` — same connection string, one pool. Short-circuits with a 500 and code `MISSING_CONNECTION_STRING` when no connection string is available. Authorization is the caller's responsibility: RLS is not consulted, so per-user scoping must be an explicit `where` clause. ### WithPostgresAdminClientConfig ```ts interface WithPostgresAdminClientConfig { connectionString?: string } ``` Defaults to the `SUPABASE_DB_URL` environment variable. --- ## @supabase/server/oauth-protected-resource > **Alpha.** The config shape, the contributed context key, and the metadata > route may change in a minor release. Also re-exported from `@supabase/server`. See [`docs/mcp.md`](mcp.md) for the MCP server walkthrough. ### withOAuthProtectedResource ```ts function withOAuthProtectedResource( config?: OAuthProtectedResourceConfig, ): Entry<{ oauthProtectedResource: OAuthProtectedResourceContribution }> function withOAuthProtectedResource(handler: FetchHandler): FetchHandler function withOAuthProtectedResource( config: OAuthProtectedResourceConfig, handler: FetchHandler, ): FetchHandler ``` OAuth 2.1 Protected Resource behavior (RFC 9728) for the wrapped handler. Answers `GET` and `OPTIONS` on any path ending in `/oauth-protected-resource` with the metadata document and a permissive CORS preflight; adds `WWW-Authenticate: Bearer resource_metadata="…"` to a `401` from below unless the handler already set that header; passes everything else through. Runs before the `withSupabase` gate; placing it directly after `withSupabase` with a credentialed auth mode is refused when the stack is built. Contributes `ctx.oauthProtectedResource.resourceMetadataUrl`, the resolved absolute URL of the metadata document. ### OAuthProtectedResourceConfig | Option | Type | Default on Supabase Edge Functions | Default elsewhere | | --------------------- | ----------- | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `resourceServer` | `UrlOption` | Public origin from `X-Forwarded-*` (or `SUPABASE_PUBLIC_URL`) + `/functions/v1/{SUPABASE_FUNCTION_SLUG}` | None. Throws `MissingResourceServerError` (`MISSING_RESOURCE_SERVER`). | | `authorizationServer` | `UrlOption` | Public origin + `/auth/v1` | `SUPABASE_PUBLIC_URL`, then `SUPABASE_URL`, each + `/auth/v1`. Throws `MissingAuthorizationServerError` (`MISSING_AUTHORIZATION_SERVER`) if neither is set. | `UrlOption` is `string | ((req: Request) => string)`. Without `SUPABASE_FUNCTION_SLUG` the resource path is reconstructed from the request path with `/functions/v1` restored; a request at the root path with no slug throws `MissingResourceServerError`. ### fromSupabaseUrl ```ts function fromSupabaseUrl(supabaseUrl: string): string ``` Turns a project URL (`https://.supabase.co`) into its Auth issuer (`…/auth/v1`) for `authorizationServer`. Tolerates a value that already carries the `/auth/v1` path. ### resourceMetadataResponse / unauthorizedResponse ```ts function resourceMetadataResponse( req: Request, options?: { resource?: string; authorizationServers?: string[] }, ): Response function unauthorizedResponse( req: Request, options?: { resourceMetadataUrl?: string }, ): Response ``` The building blocks behind the middleware, for custom routing. Defaults derive from the request as above. ## Types ### AuthMode ```ts type AuthMode = 'none' | 'publishable' | 'secret' | 'user' ``` ### AuthModeWithKey ```ts type AuthModeWithKey = AuthMode | `publishable:${string}` | `secret:${string}` ``` Extended auth mode with named key support. Examples: `'publishable:web'`, `'secret:*'`, `'secret:internal'`. The bare form (`'publishable'` / `'secret'`) matches only the `default` key; `:*` accepts any key in the set. ### CredentialedAuthMode ```ts type CredentialedAuthMode = Exclude ``` Every `AuthModeWithKey` except `'none'`, keyed forms included. ### AuthConfig ```ts type AuthConfig = | 'none' | CredentialedAuthMode | [CredentialedAuthMode, ...CredentialedAuthMode[]] | [CredentialedAuthMode, ...CredentialedAuthMode[], 'none'] ``` The accepted shape of the `auth` option. `'none'` matches every request, so the type allows it on its own or as the last entry of a list, and nowhere else — `['none']` says nothing that a bare `'none'` doesn't, and a mode placed after `'none'` can never be reached. A single mode needs no wrapping array: `'user'` and `['user']` are the same configuration. ```ts withSupabase({ auth: 'user' }, handler) // one mode withSupabase({ auth: ['secret', 'user'] }, handler) // first match wins withSupabase({ auth: ['user', 'none'] }, handler) // optional user withSupabase({ auth: 'none' }, handler) // no credentials required ``` ### Allow / AllowWithKey (deprecated aliases) `Allow` and `AllowWithKey` are kept as deprecated aliases for `AuthMode` and `AuthModeWithKey`. Prefer the `Auth*` names — the legacy ones will be removed in a future major release. ### SupabaseContext\ ```ts interface SupabaseContext { supabase: SupabaseClient supabaseAdmin: SupabaseClient userClaims: UserClaims | null jwtClaims: JWTClaims | null authMode: AuthMode authKeyName?: string } ``` ### WithSupabaseConfig ```ts interface WithSupabaseConfig { auth?: AuthConfig // default: 'user' /** @deprecated use `auth` instead — will be removed in a future major release */ allow?: AuthModeWithKey | AuthModeWithKey[] env?: Partial cors?: boolean | Record // default: true supabaseOptions?: SupabaseClientOptions errors?: ErrorResponseConfig } ``` ### ErrorResponseConfig ```ts interface ErrorResponseConfig { detailed?: boolean // default: true } ``` `detailed: false` reduces the error response body to `code` and `message` alone, dropping `source`, `hint`, `docs`, and `details`. The status and `x-supabase-server-error` header are unaffected, and the error object itself keeps everything. See [`error-handling.md`](error-handling.md#trimming-the-response-body). ### SupabaseEnv ```ts interface SupabaseEnv { url: string publishableKeys: Record secretKeys: Record jwks: JsonWebKeySet | null } ``` ### Credentials ```ts interface Credentials { token: string | null apikey: string | null } ``` ### AuthResult ```ts interface AuthResult { authMode: AuthMode token: string | null userClaims: UserClaims | null jwtClaims: JWTClaims | null keyName?: string | null } ``` ### JWTClaims ```ts interface JWTClaims { sub: string iss?: string aud?: string | string[] exp?: number iat?: number role?: string email?: string app_metadata?: Record user_metadata?: Record [key: string]: unknown } ``` ### UserClaims ```ts interface UserClaims { id: string role?: string email?: string appMetadata?: Record userMetadata?: Record } ``` ### ClientAuth ```ts interface ClientAuth { token?: string | null keyName?: string | null } ``` ### CreateContextClientOptions ```ts interface CreateContextClientOptions { auth?: ClientAuth env?: Partial supabaseOptions?: SupabaseClientOptions } ``` ### CreateAdminClientOptions ```ts interface CreateAdminClientOptions { auth?: Pick env?: Partial supabaseOptions?: SupabaseClientOptions } ``` ### JsonWebKeySet ```ts interface JsonWebKeySet { keys: JsonWebKey[] } ``` ### Peer Dependencies Some peer dependencies types are available from `@supabase/server/peer/*` export #### supabase-js Only a curated set of types are available to import — It means that may be missing types from the original lib. ```ts import type { SupabaseClient, PostgrestError, AuthError as SupabaseAuthError, // Avoid clashing with this SDK's own `AuthError` class. // ... } from '@supabase/server/peer/supabase-js' ``` --- ## Error Classes ### SupabaseServerError Base class for every error the library produces — catch this to handle anything from `@supabase/server`. ```ts abstract class SupabaseServerError extends Error { readonly source: '@supabase/server' abstract readonly status: number readonly code: string readonly hint?: string // actionable next step readonly docs: string // link to docs/error-handling.md# readonly details?: Record // non-sensitive diagnostics toJSON(): ErrorPayload } ``` `message` is always prefixed `[@supabase/server]`. `details` never contains key values or token payloads. `toJSON()` is picked up by `JSON.stringify`, so logging the error yields the full diagnostics. ### EnvError ```ts class EnvError extends SupabaseServerError { readonly status: 500 constructor( message: string, code?: string, options?: SupabaseServerErrorOptions, ) } ``` ### AuthError ```ts class AuthError extends SupabaseServerError { readonly status: number // 401 = bad credentials, 500 = server misconfigured constructor( message: string, code?: string, status?: number, options?: SupabaseServerErrorOptions, ) } ``` ### ErrorPayload The JSON body every auto-responding layer returns, and the return type of `toJSON()`. ```ts interface ErrorPayload { source: '@supabase/server' code: string message: string hint?: string docs: string details?: Record } ``` ### SupabaseServerErrorOptions ```ts interface SupabaseServerErrorOptions { hint?: string details?: Record docs?: string // overrides the generated URL cause?: unknown } ``` --- ## Error Code Constants | Constant | Value | Class | Meaning | | ----------------------------------- | ----------------------------------- | ----------- | -------------------------------------------------------------------- | | `EnvGenericError` | `'ENV_ERROR'` | `EnvError` | Generic environment error | | `MissingSupabaseURLError` | `'MISSING_SUPABASE_URL'` | `EnvError` | `SUPABASE_URL` not set | | `MissingPublishableKeyError` | `'MISSING_PUBLISHABLE_KEY'` | `EnvError` | Named publishable key not found | | `MissingDefaultPublishableKeyError` | `'MISSING_DEFAULT_PUBLISHABLE_KEY'` | `EnvError` | No default publishable key | | `MissingSecretKeyError` | `'MISSING_SECRET_KEY'` | `EnvError` | Named secret key not found | | `MissingDefaultSecretKeyError` | `'MISSING_DEFAULT_SECRET_KEY'` | `EnvError` | No default secret key | | `MissingResourceServerError` | `'MISSING_RESOURCE_SERVER'` | `EnvError` | `withOAuthProtectedResource` cannot derive a `resourceServer` | | `MissingAuthorizationServerError` | `'MISSING_AUTHORIZATION_SERVER'` | `EnvError` | `withOAuthProtectedResource` cannot derive an authorization server | | `MissingConnectionStringError` | `'MISSING_CONNECTION_STRING'` | `EnvError` | No Postgres connection string configured | | `AuthGenericError` | `'AUTH_ERROR'` | `AuthError` | Generic auth error (401) | | `MissingCredentialsError` | `'MISSING_CREDENTIALS'` | `AuthError` | Request carried no credentials at all (401) | | `UnusableCredentialError` | `'UNUSABLE_CREDENTIAL'` | `AuthError` | A credential arrived but cannot be used (401) | | `InvalidApiKeyError` | `'INVALID_API_KEY'` | `AuthError` | `apikey` matched no configured key (401) | | `InvalidJwtError` | `'INVALID_JWT'` | `AuthError` | JWT failed verification (401) | | `InvalidCredentialsError` | `'INVALID_CREDENTIALS'` | `AuthError` | Fallback credential failure (401) | | `JwksNotConfiguredError` | `'JWKS_NOT_CONFIGURED'` | `AuthError` | JWT sent but no JWKS configured (500) | | `JwksFetchFailedError` | `'JWKS_FETCH_FAILED'` | `AuthError` | Remote JWKS unreachable or unusable (500) | | `NoKeysConfiguredError` | `'NO_KEYS_CONFIGURED'` | `AuthError` | Auth mode no configured key can match (500) | | `UnsupportedRoleError` | `'UNSUPPORTED_ROLE'` | `AuthError` | `withPostgresClient` will not assume the caller's `role` claim (500) | | `CreateSupabaseClientError` | `'CREATE_SUPABASE_CLIENT_ERROR'` | `AuthError` | Client creation failed after auth (500) | Also exported: `ErrorSource` (`'@supabase/server'`) and `ErrorCodeHeader` (`'x-supabase-server-error'`). See [`error-handling.md`](error-handling.md) for the meaning, `hint`, and `details` of each code. --- ## Errors Factory Map ```ts const Errors: { [MissingSupabaseURLError]: () => EnvError [MissingPublishableKeyError]: (name, configuredKeyNames?) => EnvError [MissingDefaultPublishableKeyError]: (configuredKeyNames?) => EnvError [MissingSecretKeyError]: (name, configuredKeyNames?) => EnvError [MissingDefaultSecretKeyError]: (configuredKeyNames?) => EnvError [MissingResourceServerError]: () => EnvError [MissingAuthorizationServerError]: () => EnvError [MissingConnectionStringError]: (middleware: string) => EnvError [MissingCredentialsError]: (context: AuthFailureContext) => AuthError [UnusableCredentialError]: ( context: PartialContext & { reason; hint }, ) => AuthError [InvalidApiKeyError]: (context: AuthFailureContext) => AuthError [InvalidJwtError]: (context: PartialContext & JwtFailure) => AuthError [InvalidCredentialsError]: (context?: AuthFailureContext) => AuthError [JwksNotConfiguredError]: ( context?: PartialContext & { middleware? }, ) => AuthError [JwksFetchFailedError]: (context: PartialContext & { reason }) => AuthError [NoKeysConfiguredError]: ( context: AuthFailureContext & { mode; keyKind }, ) => AuthError [UnsupportedRoleError]: (context: { requestedRole supportedRoles }) => AuthError [CreateSupabaseClientError]: (options?: { cause?: unknown }) => AuthError } ``` Keyed by error code constant. Each entry returns an error pre-configured with `hint`, `docs`, and non-sensitive `details`. The named-key factories accept the configured key names so they can be reported in the message without exposing key values. ### AuthFailureContext Non-sensitive diagnostics the auth pipeline passes to the factories. ```ts interface AuthFailureContext { authModes: readonly string[] received: { authorization: 'bearer' | 'api-key' | 'non-bearer-scheme' | 'absent' apikey: 'absent' | 'publishable' | 'secret' | 'legacy-jwt' | 'unrecognized' } configuredKeyNames?: Record matchedKey?: { kind: 'publishable' | 'secret'; name: string; mode: string } } ```