服务器 Client Library
@supabase/serverView on GitHub@supabase/server is a framework-agnostic library for authenticating requests in server-side JavaScript environments. It verifies JWTs, resolves Supabase API keys, and creates pre-configured Supabase clients — exposing everything through a single SupabaseContext that is identical regardless of which adapter or primitive produced it.
Adapters for Hono, H3, Elysia, and NestJS are included. You can also compose the lower-level primitives directly for custom frameworks or edge runtimes.
Not sure this is the right package? See which package to use — for cookie-based sessions in SSR frameworks, use @supabase/ssr instead.
Installing
Install as a package#
Install @supabase/server via your package manager.
1npm install @supabase/serverUse via JSR (Deno / Bun)#
@supabase/server is also published to JSR for Deno and Bun environments.
1deno add jsr:@supabase/servercreateSupabaseContext
createSupabaseContext(request, options?)Creates a SupabaseContext directly from a request.
Use this when you need the context without the full withSupabase wrapper — e.g., inside framework route handlers or custom middleware. Returns a result tuple instead of producing a Response.
Parameters
- requestRequest
The incoming HTTP request.
- optionsOptionalWithSupabaseConfig
Auth modes, environment overrides. The
corsoption is ignored here.
Return Type
- Option 1object
- Option 2object
1const { data: ctx, error } = await createSupabaseContext(request, { auth: 'user' })2if (error) {3 return Response.json({ message: error.message }, { status: error.status })4}5const { data } = await ctx.supabase.rpc('get_my_items')withSupabase
withSupabase(config, handler)Wraps a request handler with Supabase auth, client creation, and CORS handling.
Built for the Web API Request/Response standard that all modern runtimes implement natively. Handles CORS preflight, credential verification, context creation, and error responses. Your handler only runs on successful auth.
Parameters
- configWithSupabaseConfig
Auth modes, CORS, and environment overrides. See WithSupabaseConfig.
- handlerfunction
Receives the
Requestand a fully-initialized SupabaseContext.
Return Type
1import { withSupabase } from '@supabase/server'23export default {4 fetch: withSupabase({ auth: 'user' }, async (req, ctx) => {5 const { data } = await ctx.supabase.rpc('get_my_profile')6 return Response.json(data)7 }),8}createAdminClient
createAdminClient(options?)Creates an admin Supabase client that bypasses Row-Level Security.
Uses a secret key for authentication, giving full access to all data. Stateless — one client per request.
Which key is used#
With auth.keyName set, that named key from SUPABASE_SECRET_KEYS is used — and it throws if the key doesn't exist. With keyName omitted, the default key is used, falling back to the first key in the set when no default exists.
Note this differs from the "secret" auth mode, which matches the default key only and never falls back — see index.AuthModeWithKey.
Parameters
- optionsOptionalCreateAdminClientOptions
1// Uses the `default` secret key (or the first key if no `default` exists)2const supabaseAdmin = createAdminClient()3const { data } = await supabaseAdmin.from('audit_log').insert({ action: 'user_login' })createContextClient
createContextClient(options?)Creates a Supabase client scoped to the caller's context.
Configured with a publishable key and (optionally) the caller's JWT, so Row-Level Security policies apply. Stateless — one client per request.
Which key is used#
With auth.keyName set, that named key from SUPABASE_PUBLISHABLE_KEYS is used — and it throws if the key doesn't exist. With keyName omitted, the default key is used, falling back to the first key in the set when no default exists.
Note this differs from the "publishable" auth mode, which matches the default key only and never falls back — see index.AuthModeWithKey.
Parameters
- optionsOptionalCreateContextClientOptions
1const { data: auth } = await verifyAuth(request, { auth: 'user' })2const supabase = createContextClient({3 auth: { token: auth.token, keyName: auth.keyName },4})5const { data } = await supabase.rpc('get_my_items')extractCredentials
extractCredentials(request)Extracts authentication credentials from an incoming HTTP request.
Reads two headers:
Authorization: Bearer <token>→ extracted astokenapikey: <key>→ extracted asapikey
This is a pure extraction step — no validation or verification is performed. Pass the result to verifyCredentials to validate against allowed auth modes.
Parameters
- requestRequest
The incoming HTTP request.
Return Type
1import { extractCredentials } from '@supabase/server/core'23const creds = extractCredentials(request)4console.log(creds.token) // "eyJhbGci..." or null5console.log(creds.apikey) // "sb-abc123-publishable-..." or nullresolveEnv
resolveEnv(overrides?)Resolves Supabase environment configuration from runtime environment variables.
Reads SUPABASE_URL, keys (SUPABASE_PUBLISHABLE_KEYS / SUPABASE_SECRET_KEYS), and the JWKS source (SUPABASE_JWKS for inline keys, or SUPABASE_JWKS_URL for a remote endpoint). Works across Deno, Node.js, and Bun. For Cloudflare Workers, use overrides or enable node-compat.
Parameters
- overridesOptionalPartial
Partial values that take precedence over env vars.
Return Type
- Option 1object
- Option 2object
1const { data: env, error } = resolveEnv()2if (error) throw error34// Override for tests5const { data: env } = resolveEnv({ url: 'http://localhost:54321' })verifyAuth
verifyAuth(request, options)Extracts credentials from a request and verifies them in a single step.
This is a convenience function that combines extractCredentials and verifyCredentials. Use it when you want the full auth flow without needing to inspect the raw credentials.
Parameters
- requestRequest
The incoming HTTP request.
- optionsVerifyAuthOptions
Auth modes to accept and optional environment overrides.
Return Type
- Option 1object
- Option 2object
1import { verifyAuth } from '@supabase/server/core'23const { data: auth, error } = await verifyAuth(request, {4 auth: 'user',5})67if (error) {8 return Response.json({ message: error.message }, { status: error.status })9}1011console.log(auth.userClaims!.id) // "d0f1a2b3-..."VerifyAuthOptions
VerifyAuthOptions(auth?, allow?, env?)Options for verifyAuth.
Parameters
- authOptionalOne of the following options
Auth mode(s) to try. Modes are attempted in order — the first match wins.
- Option 1One of the following options
- Option 1One of the following options
- Option 1"none"
- Option 2"publishable"
- Option 3"secret"
- Option 4"user"
- Option 2
- Option 3
- Option 2Array<One of the following options>
- allowOptionalOne of the following options
- Option 1One of the following options
- Option 1One of the following options
- Option 1"none"
- Option 2"publishable"
- Option 3"secret"
- Option 4"user"
- Option 2
- Option 3
- Option 2Array<One of the following options>
- envOptionalPartial
Optional environment overrides (passed through to resolveEnv).
verifyCredentials
verifyCredentials(credentials, options)Verifies pre-extracted credentials against one or more allowed auth modes.
Tries each mode in order — first match wins. A mode is only tried when its credential is present; a JWT that is present but fails verification short-circuits the chain with InvalidCredentialsError instead of falling through to the next mode. Use verifyAuth to extract and verify in a single call.
Parameters
- credentialsCredentials
The credentials to verify (from extractCredentials).
- optionsVerifyCredentialsOptions
Allowed auth modes and optional env overrides.
Return Type
- Option 1object
- Option 2object
1const credentials = extractCredentials(request)2const { data: auth, error } = await verifyCredentials(credentials, {3 auth: ['user', 'publishable'],4})5if (error) {6 return Response.json({ message: error.message }, { status: error.status })7}VerifyCredentialsOptions
VerifyCredentialsOptions(auth?, allow?, env?)Options for verifyCredentials.
Parameters
- authOptionalOne of the following options
Auth mode(s) to try. Modes are attempted in order — the first match wins.
- Option 1One of the following options
- Option 1One of the following options
- Option 1"none"
- Option 2"publishable"
- Option 3"secret"
- Option 4"user"
- Option 2
- Option 3
- Option 2Array<One of the following options>
- allowOptionalOne of the following options
- Option 1One of the following options
- Option 1One of the following options
- Option 1"none"
- Option 2"publishable"
- Option 3"secret"
- Option 4"user"
- Option 2
- Option 3
- Option 2Array<One of the following options>
- envOptionalPartial
Optional environment overrides (passed through to resolveEnv).
SupabaseError
SupabaseError(status, cause)Wraps an AuthError as an Elysia-compatible error.
Discriminate in onError via code === 'SupabaseError'. The original AuthError is available as the typed .cause.
Parameters
- statusRequirednumber
- causeRequiredAuthError
withSupabase
withSupabase(config?)Elysia plugin that creates a SupabaseContext and makes it available in route handlers.
Skips if a previous plugin already set the context, enabling route-level overrides. Throws a SupabaseError on auth failure. .status is on the error directly; the original AuthError is available as the typed .cause. Discriminate in onError via code === 'SupabaseError'.
Parameters
- configOptionalOmit
Auth modes and optional environment overrides. CORS is excluded — use Elysia's CORS utilities.
1import { Elysia } from 'elysia'2import { withSupabase } from '@supabase/server/adapters/elysia'34const app = new Elysia()5 .use(withSupabase({ auth: 'user' }))6 .get('/games', async ({ supabaseContext }) => {7 const { data } = await supabaseContext.supabase.from('favorite_games').select()8 return data9 })1011app.listen(3000)AuthError
AuthError(status, code)Thrown when authentication or authorization fails.
Carries an HTTP status code suitable for returning directly in a response (typically 401 for invalid credentials, 500 for server-side auth failures).
Parameters
- statusRequirednumber
HTTP status code.
401— Invalid or missing credentials500— Server-side auth failure (e.g., missing JWKS, env misconfiguration)
- codeRequiredstring
Machine-readable error code.
1import { AuthError, createSupabaseContext } from '@supabase/server'23const { data: ctx, error } = await createSupabaseContext(request, { auth: 'user' })4if (error) {5 // error is an AuthError6 return Response.json(7 { message: error.message, code: error.code },8 { status: error.status },9 )10}AuthGenericError
Generic authentication error code.
CreateSupabaseClientError
Failed to create a Supabase client after auth succeeded.
EnvError
EnvError(status, code)Thrown when a required environment variable is missing or malformed.
Always has status: 500 — environment errors are server-side configuration issues.
Parameters
- statusRequired"500"
Always
500— environment errors are server-side issues. - codeRequiredstring
Machine-readable error code.
1import { EnvError } from '@supabase/server'23try {4 const client = createAdminClient()5} catch (e) {6 if (e instanceof EnvError) {7 console.error(`Config issue [${e.code}]: ${e.message}`)8 // → "Config issue [MISSING_SUPABASE_URL]: SUPABASE_URL is required but not set"9 }10}EnvGenericError
Generic environment error code.
Errors
Factory map for all error types. Keyed by error code constant, each entry returns a pre-configured EnvError or AuthError.
1throw Errors[MissingSupabaseURLError]()2throw Errors[MissingPublishableKeyError]('mobile')InvalidCredentialsError
No credential matched any allowed auth mode.
MissingDefaultPublishableKeyError
No default publishable key found.
MissingDefaultSecretKeyError
No default secret key found.
MissingPublishableKeyError
Named publishable key not found in SUPABASE_PUBLISHABLE_KEYS.
MissingSecretKeyError
Named secret key not found in SUPABASE_SECRET_KEYS.
MissingSupabaseURLError
SUPABASE_URL is not set.
Allow
Deprecated. Use AuthMode instead. Will be removed in a future major release.
AllowWithKey
Deprecated. Use AuthModeWithKey instead. Will be removed in a future major release.
AuthMode
Authentication mode that determines what credentials a request must provide.
"none"— No credentials required. Every request is accepted."publishable"— Requires a valid publishable key in theapikeyheader. Matches only thedefaultkey."secret"— Requires a valid secret key in theapikeyheader (timing-safe comparison). Matches only thedefaultkey."user"— Requires a valid JWT in theAuthorization: Bearer <token>header.
Bare "publishable" / "secret" resolve the default key from SUPABASE_PUBLISHABLE_KEYS / SUPABASE_SECRET_KEYS. To target another key or accept any key, see AuthModeWithKey.
1// Single mode2withSupabase({ auth: 'user' }, handler)34// Multiple modes — the first match wins.5// A mode is tried only when its credential is present; a JWT that is6// present but fails verification rejects immediately rather than falling7// through to the next mode.8withSupabase({ auth: ['user', 'publishable'] }, handler)AuthModeWithKey
Extended auth mode that supports targeting a specific named key.
Use the colon syntax ("publishable:web_app") to require a specific named key from the SUPABASE_PUBLISHABLE_KEYS or SUPABASE_SECRET_KEYS JSON object. Use "publishable:*" or "secret:*" to accept any key in the set. The bare form without a colon ("publishable" / "secret") matches only the default key.
1// Accept only the "mobile" publishable key2withSupabase({ auth: 'publishable:mobile' }, handler)34// Accept any secret key5withSupabase({ auth: 'secret:*' }, handler)67// Mix named keys with other modes8withSupabase({ auth: ['user', 'publishable:web_app'] }, handler)AuthResult
AuthResult(authMode, token, userClaims, jwtClaims, keyName?)Result of credential verification.
Contains the resolved auth mode, the verified token (for "user" mode), decoded JWT claims, and the matched key name (for "publishable" / "secret" modes).
Parameters
- authModeRequiredOne of the following options
The auth mode that was successfully matched.
- Option 1"none"
- Option 2"publishable"
- Option 3"secret"
- Option 4"user"
- tokenRequiredOne of the following options
The verified JWT, or
nullfor non-user auth modes.- Option 1string
- Option 2null
- userClaimsRequiredOne of the following options
Normalized user identity derived from the JWT, or
nullwhen no JWT is present.- Option 1UserClaims
- Option 2null
- jwtClaimsRequiredOne of the following options
Raw JWT payload, or
nullwhen no JWT is present.- Option 1JWTClaims
- Option 2null
- keyNameOptionalOne of the following options
Name of the matched key (e.g.
"default","mobile"), ornullfor"user"/"none"modes.- Option 1string
- Option 2null
ClientAuth
ClientAuth(token?, keyName?)Auth identity for client creation functions.
Parameters
- tokenOptionalOne of the following options
The caller's JWT, or
nullfor anonymous access.- Option 1string
- Option 2null
- keyNameOptionalOne of the following options
Name of the API key to use. Falls back to
"default", then first available.- Option 1string
- Option 2null
CreateAdminClientOptions
CreateAdminClientOptions(auth?, env?, supabaseOptions?)Options for core.createAdminClient.
Parameters
- authOptional
Auth identity — key name from the verified request.
- envOptionalPartial
Override auto-detected environment variables.
- supabaseOptionsOptionalSupabaseClientOptions
Options forwarded to
createClient().accessTokenis stripped; auth settings are force-overwritten.
CreateContextClientOptions
CreateContextClientOptions(auth?, env?, supabaseOptions?)Options for core.createContextClient.
Parameters
- authOptionalClientAuth
Auth identity — token and key name from the verified request.
- envOptionalPartial
Override auto-detected environment variables.
- supabaseOptionsOptionalSupabaseClientOptions
Options forwarded to
createClient().accessTokenis stripped; auth settings are force-overwritten.
Credentials
Credentials(token, apikey)Raw credentials extracted from an incoming HTTP request.
Produced by core.extractCredentials from the Authorization and apikey headers.
Parameters
- tokenRequiredOne of the following options
Bearer token from the
Authorization: Bearer <token>header, ornullif absent.- Option 1string
- Option 2null
- apikeyRequiredOne of the following options
API key from the
apikeyheader, ornullif absent.- Option 1string
- Option 2null
JWTClaims
JWTClaims(sub, iss?, aud?, exp?, iat?, role?, email?, app_metadata?, user_metadata?)Standard JWT claims as defined by RFC 7519, extended with Supabase-specific fields.
This is the raw JWT payload — use UserClaims for a normalized, camelCase view.
Parameters
- subRequiredstring
Subject — the user's unique ID.
- issOptionalstring
Issuer — typically your Supabase project URL.
- audOptionalOne of the following options
Audience — who the token is intended for.
- Option 1string
- Option 2Array<string>
- expOptionalnumber
Expiration time (seconds since epoch).
- iatOptionalnumber
Issued at (seconds since epoch).
- roleOptionalstring
Supabase role (e.g.
"authenticated","anon"). - emailOptionalstring
User's email address from Supabase Auth.
- app_metadataOptionalRecord<string, unknown>
Application-level metadata set via Supabase Auth admin APIs.
- user_metadataOptionalRecord<string, unknown>
User-editable metadata set via Supabase Auth.
SupabaseContext
SupabaseContext(supabase, supabaseAdmin, userClaims, jwtClaims, authMode, authKeyName?)The Supabase context created for each authenticated request.
Contains pre-configured Supabase clients and the caller's identity. Identical regardless of which layer or adapter produced it.
Parameters
- supabaseRequiredSupabaseClient
Supabase client scoped to the caller's identity. RLS policies apply.
- supabaseAdminRequiredSupabaseClient
Admin Supabase client that bypasses Row-Level Security.
- userClaimsRequiredOne of the following options
JWT-derived identity. For the full Supabase User object, call
supabase.auth.getUser().- Option 1UserClaims
- Option 2null
- jwtClaimsRequiredOne of the following options
Raw JWT payload.
nullfor non-user auth modes.- Option 1JWTClaims
- Option 2null
- authModeRequiredOne of the following options
The auth mode that was used for this request.
- Option 1"none"
- Option 2"publishable"
- Option 3"secret"
- Option 4"user"
- authKeyNameOptionalstring
The auth key name of the API key that was used for this request. Omitted for
'user'and'none'modes, which don't match a named key.
SupabaseEnv
SupabaseEnv(url, publishableKeys, secretKeys, jwks)Resolved Supabase environment configuration.
Holds the project URL, API keys, and JWKS needed by every other primitive. Typically resolved automatically from environment variables by core.resolveEnv, but can be passed explicitly via the env option.
Parameters
- urlRequiredstring
Supabase project URL (e.g.
"https://<ref>.supabase.co"). Sourced fromSUPABASE_URL. - publishableKeysRequiredRecord<string, string>
Named publishable keys. Sourced from
SUPABASE_PUBLISHABLE_KEYS(JSON object) orSUPABASE_PUBLISHABLE_KEY(single key, stored as{ default: "<value>" }). - secretKeysRequiredRecord<string, string>
Named secret keys. Sourced from
SUPABASE_SECRET_KEYS(JSON object) orSUPABASE_SECRET_KEY(single key, stored as{ default: "<value>" }). - jwksRequiredOne of the following options
JWKS source used for JWT verification.
Sourced from one of (in priority order):
SUPABASE_JWKS— inline JSON. Resolves to aJSONWebKeySet.SUPABASE_JWKS_URL— remote endpoint. Resolves to aURL; keys are fetched lazily and cached in memory (cooldown / max-age handled byjose).https://is always accepted; plainhttp://is accepted only for loopback hosts (localhost,127.0.0.0/8,::1) to support the Supabase CLI. Any otherhttp://URL is rejected to prevent MITM swap-in of a forged signing key.
nullwhen no JWKS is configured (JWT verification will be unavailable). Each env var is authoritative when set: a malformed value resolves tonullrather than falling through to the other variable.- Option 1JSONWebKeySet
- Option 2URL
- Option 3null
UserClaims
UserClaims(id, role?, email?, appMetadata?, userMetadata?)Normalized, camelCase view of the authenticated user's identity.
Derived from JWTClaims. For the full Supabase User object (including email confirmation status, providers, etc.), call supabase.auth.getUser() using the context client.
Parameters
- idRequiredstring
User's unique ID (same as
JWTClaims.sub). - roleOptionalstring
Supabase role (e.g.
"authenticated"). - emailOptionalstring
User's email address.
- appMetadataOptionalRecord<string, unknown>
Application-level metadata (e.g. roles, permissions).
- userMetadataOptionalRecord<string, unknown>
User-editable profile metadata (e.g. display name, avatar).
WithSupabaseConfig
WithSupabaseConfig(auth?, allow?, env?, cors?, supabaseOptions?)Configuration for withSupabase and createSupabaseContext.
Controls which auth modes are accepted, environment overrides, and CORS behavior.
Parameters
- authOptionalOne of the following options
Auth mode(s) to accept. Modes are tried in order — the first match wins. A mode falls through only when its credential is absent; a present-but-invalid JWT short-circuits the chain with
InvalidCredentialsError.- Option 1One of the following options
- Option 1One of the following options
- Option 1"none"
- Option 2"publishable"
- Option 3"secret"
- Option 4"user"
- Option 2
- Option 3
- Option 2Array<One of the following options>
- allowOptionalOne of the following options
- Option 1One of the following options
- Option 1One of the following options
- Option 1"none"
- Option 2"publishable"
- Option 3"secret"
- Option 4"user"
- Option 2
- Option 3
- Option 2Array<One of the following options>
- envOptionalPartial
Override auto-detected environment variables. Useful for testing or when running in environments without standard env var support.
- corsOptionalOne of the following options
CORS configuration for the
withSupabasewrapper.'default'— uses@supabase/supabase-jsdefault CORS headers.'disabled'— disables CORS handling entirely.{ headers }— custom CORS headers.
The boolean (
true/false) and bareRecord<string, string>forms are deprecated but still accepted for backward compatibility.- Option 1boolean
- Option 2Record<string, string>
- Option 3"default"
- Option 4"disabled"
- Option 5object
- supabaseOptionsOptionalSupabaseClientOptions
Options forwarded to both internal
createClient()calls.accessTokenis stripped, and auth settings (persistSession,autoRefreshToken,detectSessionInUrl) are force-overwritten to server-safe values.
1// Require authenticated users, auto-CORS enabled (default)2const config: WithSupabaseConfig = { auth: 'user' }34// Accept users or service-to-service calls, custom CORS headers5const config: WithSupabaseConfig = {6 auth: ['user', 'secret'],7 cors: { 'Access-Control-Allow-Origin': 'https://myapp.com' },8}910// No auth required, CORS disabled11const config: WithSupabaseConfig = { auth: 'none', cors: 'disabled' }