@supabase/server - v1.7.0
    Preparing search index...

    API Reference

    Complete reference for every export, organized by entry point.


    function withSupabase<Database = UntypedDatabase>(
    config: WithSupabaseConfig,
    handler: (req: Request, ctx: SupabaseContext<Database>) => Promise<Response>,
    ): (req: Request) => Promise<Response>

    Wraps a fetch handler with auth, CORS, and client creation. Returns a (req: Request) => Promise<Response> 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().
    function withSupabase<Database = UntypedDatabase>(
    config: WithSupabaseConfig,
    ): Entry<SupabaseContext<Database>>

    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:

    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.

    function createSupabaseContext<Database = UntypedDatabase>(
    request: Request,
    options?: WithSupabaseConfig,
    ): Promise<
    | { data: SupabaseContext<Database>; 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.


    function verifyAuth(
    request: Request,
    options: {
    auth?: AuthModeWithKey | AuthModeWithKey[]
    audience?: string | string[]
    issuer?: string | string[]
    env?: Partial<SupabaseEnv>
    },
    ): Promise<{ data: AuthResult; error: null } | { data: null; error: AuthError }>

    Extracts credentials from a request and verifies them. Convenience wrapper over extractCredentials + verifyCredentials. audience and issuer apply to user mode; see WithSupabaseConfig.

    function verifyCredentials(
    credentials: Credentials,
    options: {
    auth?: AuthModeWithKey | AuthModeWithKey[]
    audience?: string | string[]
    issuer?: string | string[]
    env?: Partial<SupabaseEnv>
    },
    ): 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. audience and issuer apply to user mode; see WithSupabaseConfig.

    function extractCredentials(request: Request): Credentials
    

    Reads Authorization: Bearer <token> and apikey headers from a request. Pure extraction, no validation. Synchronous.

    function resolveEnv(
    overrides?: Partial<SupabaseEnv>,
    ): { data: SupabaseEnv; error: null } | { data: null; error: EnvError }

    Resolves Supabase environment configuration from runtime variables. SUPABASE_URL is the only hard requirement.

    function createContextClient<Database = UntypedDatabase>(
    options?: CreateContextClientOptions,
    ): SupabaseClient<Database>

    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
    function createAdminClient<Database = UntypedDatabase>(
    options?: CreateAdminClientOptions,
    ): SupabaseClient<Database>

    Creates an admin Supabase client that bypasses RLS. Throws EnvError if URL or secret key is missing.


    function withSupabase(
    config?: Omit<WithSupabaseConfig, 'cors'>,
    ): 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.


    function withSupabase(config?: Omit<WithSupabaseConfig, 'cors'>): 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.


    function withSupabase(config?: Omit<WithSupabaseConfig, 'cors'>): 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.


    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.

    const withClaims: Middleware<
    'jwtClaims',
    WithClaimsConfig | void,
    Record<never, never>,
    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.

    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.

    interface WithClaimsConfig {
    jwks?: JSONWebKeySet | URL
    audience?: string | string[]
    issuer?: string | string[]
    errors?: ErrorResponseConfig
    }

    jwks defaults to SUPABASE_JWKS (inline JSON) or SUPABASE_JWKS_URL (https endpoint) from the environment. audience and issuer pin the token's aud and iss claims; see WithSupabaseConfig for the rules. errors trims the short-circuit response body; see ErrorResponseConfig.


    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.

    const withRequiredClaims: Middleware<
    'jwtClaims',
    WithRequiredClaimsConfig | void,
    Record<never, never>,
    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.

    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:

    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:

    const entry = (h: (req: Request, ctx: object) => Promise<Response>) =>
    withSupabase({ auth: 'user', cors: 'disabled' }, h)
    interface WithRequiredClaimsConfig {
    jwks?: JSONWebKeySet | URL
    audience?: string | string[]
    issuer?: string | string[]
    errors?: ErrorResponseConfig
    }

    jwks defaults to SUPABASE_JWKS (inline JSON) or SUPABASE_JWKS_URL (https endpoint) from the environment. audience and issuer pin the token's aud and iss claims; see WithSupabaseConfig for the rules. errors trims the short-circuit response body; see ErrorResponseConfig.


    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.

    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.

    interface PostgresApi {
    query<T = Record<string, unknown>>(
    strings: TemplateStringsArray,
    ...values: unknown[]
    ): Promise<T[]>

    queryRaw<T = Record<string, unknown>>(
    text: string,
    params?: unknown[],
    ): Promise<T[]>
    }

    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:

    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<NoteRow>:

    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:

    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.

    interface WithPostgresClientConfig {
    connectionString?: string
    errors?: ErrorResponseConfig
    }

    connectionString defaults to the SUPABASE_DB_URL environment variable. Pools are created lazily, one per connection string per process. errors trims the short-circuit response body; see ErrorResponseConfig.

    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.


    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.

    const withPostgresAdminClient: Middleware<
    'postgresAdmin',
    WithPostgresAdminClientConfig | void,
    Record<never, never>,
    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.

    interface WithPostgresAdminClientConfig {
    connectionString?: string
    errors?: ErrorResponseConfig
    }

    connectionString defaults to the SUPABASE_DB_URL environment variable. errors trims the short-circuit response body; see ErrorResponseConfig.


    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 for the MCP server walkthrough.

    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. A default URL it cannot derive is answered with the library's JSON error response (500 and x-supabase-server-error, see Error handling); a throw from a configured resourceServer or authorizationServer function propagates.

    Contributes ctx.oauthProtectedResource.resourceMetadataUrl, the resolved absolute URL of the metadata document.

    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. Every request except the metadata route's OPTIONS preflight is answered with a 500 and code MISSING_RESOURCE_SERVER (MissingResourceServerError).
    authorizationServer UrlOption Public origin + /auth/v1 SUPABASE_PUBLIC_URL, then SUPABASE_URL, each + /auth/v1. Short-circuits with a 500 and code MISSING_AUTHORIZATION_SERVER (MissingAuthorizationServerError) if neither is set.
    errors ErrorResponseConfig { detailed: true } { detailed: true }

    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 short-circuits with a 500 and code MISSING_RESOURCE_SERVER. errors (an ErrorResponseConfig) trims the body of those 500s.

    function fromSupabaseUrl(supabaseUrl: string): string
    

    Turns a project URL (https://<ref>.supabase.co) into its Auth issuer (…/auth/v1) for authorizationServer. Tolerates a value that already carries the /auth/v1 path.

    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.

    type AuthMode = 'none' | 'publishable' | 'secret' | 'user'
    
    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.

    type CredentialedAuthMode = Exclude<AuthModeWithKey, 'none'>
    

    Every AuthModeWithKey except 'none', keyed forms included.

    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.

    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 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.

    interface SupabaseContext<Database = UntypedDatabase> {
    supabase: SupabaseClient<Database>
    supabaseAdmin: SupabaseClient<Database>
    userClaims: UserClaims | null
    jwtClaims: JWTClaims | null
    authMode: AuthMode
    authKeyName?: string
    }
    interface WithSupabaseConfig {
    auth?: AuthConfig // default: 'user'
    /** @deprecated use `auth` instead — will be removed in a future major release */
    allow?: AuthModeWithKey | AuthModeWithKey[]
    audience?: string | string[]
    issuer?: string | string[]
    env?: Partial<SupabaseEnv>
    cors?: boolean | Record<string, string> // default: true
    supabaseOptions?: SupabaseClientOptions<string>
    errors?: ErrorResponseConfig
    }

    audience and issuer apply to user mode. Each accepts a string or an array of accepted values. When an option is set, a token without that claim is rejected. A token with the claim passes when its value is in the accepted list. For an aud array on the token, one matching entry is enough. Supabase Auth sets aud to authenticated and iss to https://<project-ref>.supabase.co/auth/v1, so issuer: fromSupabaseUrl(url) pins an endpoint to one project. A failed check rejects with InvalidJwtError (INVALID_JWT).

    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. Accepted as errors by withSupabase and by every middleware that answers directly: withClaims, withRequiredClaims, withPostgresClient, withPostgresAdminClient, withOAuthProtectedResource. See error-handling.md.

    interface SupabaseEnv {
    url: string
    publishableKeys: Record<string, string>
    secretKeys: Record<string, string>
    jwks: JsonWebKeySet | null
    }
    interface Credentials {
    token: string | null
    apikey: string | null
    }
    interface AuthResult {
    authMode: AuthMode
    token: string | null
    userClaims: UserClaims | null
    jwtClaims: JWTClaims | null
    keyName?: string | null
    }
    interface JWTClaims {
    sub: string
    iss?: string
    aud?: string | string[]
    exp?: number
    iat?: number
    role?: string
    email?: string
    app_metadata?: Record<string, unknown>
    user_metadata?: Record<string, unknown>
    [key: string]: unknown
    }
    interface UserClaims {
    id: string
    role?: string
    email?: string
    appMetadata?: Record<string, unknown>
    userMetadata?: Record<string, unknown>
    }
    interface ClientAuth {
    token?: string | null
    keyName?: string | null
    }
    interface CreateContextClientOptions {
    auth?: ClientAuth
    env?: Partial<SupabaseEnv>
    supabaseOptions?: SupabaseClientOptions<string>
    }
    interface CreateAdminClientOptions {
    auth?: Pick<ClientAuth, 'keyName'>
    env?: Partial<SupabaseEnv>
    supabaseOptions?: SupabaseClientOptions<string>
    }
    interface JsonWebKeySet {
    keys: JsonWebKey[]
    }

    Some peer dependencies types are available from @supabase/server/peer/* export

    Only a curated set of types are available to import — It means that may be missing types from the original lib.

    import type {
    SupabaseClient,
    PostgrestError,
    AuthError as SupabaseAuthError, // Avoid clashing with this SDK's own `AuthError` class.
    // ...
    } from '@supabase/server/peer/supabase-js'

    Base class for every error the library produces — catch this to handle anything from @supabase/server.

    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#<code>
    readonly details?: Record<string, unknown> // 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.

    class EnvError extends SupabaseServerError {
    readonly status: 500
    constructor(
    message: string,
    code?: string,
    options?: SupabaseServerErrorOptions,
    )
    }
    class AuthError extends SupabaseServerError {
    readonly status: number // 401 = bad credentials, 500 = server misconfigured
    constructor(
    message: string,
    code?: string,
    status?: number,
    options?: SupabaseServerErrorOptions,
    )
    }

    The JSON body every auto-responding layer returns, and the return type of toJSON().

    interface ErrorPayload {
    source: '@supabase/server'
    code: string
    message: string
    hint?: string
    docs: string
    details?: Record<string, unknown>
    }
    interface SupabaseServerErrorOptions {
    hint?: string
    details?: Record<string, unknown>
    docs?: string // overrides the generated URL
    cause?: unknown
    }

    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 for the meaning, hint, and details of each code.


    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.

    Non-sensitive diagnostics the auth pipeline passes to the factories.

    interface AuthFailureContext {
    authModes: readonly string[]
    received: {
    authorization: 'bearer' | 'api-key' | 'non-bearer-scheme' | 'absent'
    apikey: 'absent' | 'publishable' | 'secret' | 'legacy-jwt' | 'unrecognized'
    }
    configuredKeyNames?: Record<string, readonly string[]>
    matchedKey?: { kind: 'publishable' | 'secret'; name: string; mode: string }
    }