Supabase OAuth 2.1 Server: When Should Your SaaS Become an Identity Provider?
Supabase Auth can do something materially different from ordinary “Sign in with Google” authentication: your Supabase-backed product can itself become an OAuth 2.1 and OpenID Connect identity provider for other applications.
That is useful when a SaaS platform wants third-party apps, partner integrations, mobile clients, enterprise tools, or MCP/AI agents to act on behalf of its existing users. It is unnecessary when all you need is login for your own web application.
The most important implementation detail is easy to miss: OAuth scopes such as __INLINE_CODE_0__, __INLINE_CODE_1__, __INLINE_CODE_2__, and __INLINE_CODE_3__ do not control access to your Postgres data. Supabase says database/API authorization still belongs in Row Level Security, where OAuth tokens can be restricted using their __INLINE_CODE_4__ claim.
So the real architecture is:
OAuth establishes who the user authorised
↓
Supabase issues the token
↓
RLS decides what that client may actually accessThis guide explains when that architecture is worth adopting and how to avoid turning “Sign in with our app” into “every integration gets the user's full normal permissions.”
What does Supabase OAuth 2.1 Server actually do?
Supabase Auth can now act as an OAuth 2.1 authorization server and OpenID Connect provider.
According to the current Supabase OAuth 2.1 Server documentation, that lets another application authenticate through your Supabase project in the same broad pattern users recognise from “Sign in with Google” or “Sign in with GitHub”.
Supabase lists use cases including:
- developer platforms and marketplaces
- third-party partner integrations
- “Sign in with Your App”
- AI agents and Model Context Protocol clients
- first-party mobile and desktop clients
- enterprise OpenID Connect integrations
The flow is no longer:
Your web app
↓
Supabase Auth
↓
Your databaseIt can become:
Third-party app
↓
Your Supabase OAuth authorization server
↓
Your login + consent UI
↓
Supabase access / refresh token
↓
Your API / Supabase dataThat turns authentication into part of your product platform.
When should a SaaS product become an identity provider?
A SaaS product should consider becoming an OAuth/OIDC provider when other software needs delegated access to user-owned capabilities or data.
That usually appears in one of four product stages.
1. You are opening a developer ecosystem
Suppose customers use a project-management SaaS and want external tools to integrate with it.
Without delegated OAuth, integrations often begin badly:
User creates long-lived API key
↓
Pastes key into third-party service
↓
Third party effectively receives broad account accessA better model is:
Third-party integration
↓
"Connect to Your SaaS"
↓
User authenticates
↓
User sees consent
↓
Short-lived access token
↓
Access constrained by application policyThe OAuth server becomes useful when integrations are a supported product surface, not an internal workaround.
2. You want "Sign in with Your App"
If your platform owns a meaningful user identity that other applications should trust, OpenID Connect can let partners authenticate users using that identity.
Examples include:
- a marketplace whose vendors use partner apps
- an education platform whose users access connected learning tools
- a property platform whose agents connect specialist services
- a B2B platform with a partner ecosystem
- a developer platform exposing user-authorised integrations
The product is effectively saying:
“This user has authenticated with our platform, and we can issue standards-based identity and access tokens.”
That is a larger responsibility than adding another social-login button to your own app.
3. AI agents or MCP clients need user-authorised access
Supabase explicitly positions OAuth 2.1 Server for Model Context Protocol authentication.
Its MCP authentication guide says an MCP server can use the existing Supabase user base so an AI client authenticates as the user who approved it, rather than receiving a shared service key.
The shape becomes:
AI / MCP client
↓
OAuth discovery
↓
Your Supabase Auth server
↓
User login + consent
↓
Access token
↓
MCP server
↓
User-authorised Supabase resourcesThis is much safer than giving an AI tool a project-wide secret.
It also creates an auditable question:
Which user authorised which OAuth client to operate on their behalf?
4. Your product needs standards-based federation
Supabase's OAuth server includes OpenID Connect support, including OIDC discovery, ID tokens with the __INLINE_CODE_0__ scope, and a UserInfo endpoint.
That can be useful where another system expects an OIDC identity provider rather than a custom JWT endpoint.
However, do not interpret “OIDC support exists” as “every enterprise SSO requirement is solved.”
Enterprise buyers may still require:
- organisation-level tenant controls
- domain discovery
- SCIM provisioning
- group/role mapping
- audit logs
- administrator consent
- lifecycle/deprovisioning workflows
- contractual/security controls
OAuth/OIDC is the protocol layer. Enterprise identity governance is a broader product.
When is Supabase OAuth Server unnecessary?
Do not enable an authorization server simply because OAuth sounds more “enterprise”.
You probably do not need it when:
- only your own web app needs login
- only your own Flutter/mobile app uses the same Supabase project and standard Supabase Auth already works
- no third-party application needs delegated user access
- integrations are server-to-server and do not act on behalf of end users
- a simple internal service account is sufficient and appropriately secured
- you are trying to fix ordinary login, session, or social-provider issues
A normal application already using:
Google / Apple / email login
↓
Supabase Auth
↓
RLSdoes not benefit simply because Supabase can also become an OAuth provider.
The feature becomes valuable when your application is the identity or authorization boundary that other clients need to cross.
OAuth provider vs OAuth client: do not confuse the two
This causes a surprising number of design mistakes.
Your app as an OAuth client
The familiar pattern:
Your app
↓
Sign in with Google
↓
Google is OAuth/OIDC providerYour app consumes identity from another provider.
Your Supabase project as an OAuth provider
The inverse:
Partner app
↓
Sign in with Your SaaS
↓
Your Supabase project is the OAuth/OIDC providerNow your system issues tokens that another client relies on.
That means you own more of the security surface:
- client registration
- redirect URI configuration
- consent experience
- token claims
- RLS authorization
- revocation
- third-party app governance
Turning on OAuth Server is therefore a platform decision, not just an authentication toggle.
How does the OAuth 2.1 flow work in Supabase?
Supabase currently supports:
- authorization code flow with PKCE
- refresh token flow
Its OAuth flow documentation says other grant types such as __INLINE_CODE_0__ and __INLINE_CODE_1__ are not supported.
A user-authorised flow looks like this:
Third-party client
↓
GET /oauth/authorize
↓
Supabase validates OAuth request
↓
Redirect to your authorization UI
↓
User authenticates
↓
Your UI shows client + requested scopes
↓
User approves or denies
↓
Authorization code
↓
Client exchanges code + PKCE verifier
↓
Access token + refresh tokenPKCE matters because it protects the authorization-code exchange from interception.
Supabase recommends the authorization code flow with PKCE for public clients, mobile apps, single-page apps, and server-side applications.
You must build the consent experience
Supabase handles the OAuth protocol, but it does not make the product decision for you.
The current getting-started guide requires you to configure an authorization path and build the frontend that:
- receives the __INLINE_CODE_0__
- confirms whether the user is authenticated
- retrieves details about the requesting client
- shows the requested information/scopes
- lets the user approve or deny
- redirects using the URL returned by Supabase
A poor consent screen says:
Allow Example App?
[Allow]A useful consent screen answers:
Who is asking?
What information is requested?
What will the integration be able to do?
Can the user deny it?
Can access be revoked later?For AI-agent access, those questions become even more important because the end user may otherwise interpret the agent as having ambient authority over their account.
The biggest trap: OAuth scopes do not secure your database
This is the most important technical detail in the current Supabase implementation.
Supabase supports standard OAuth/OIDC scopes such as:
openid
email
profile
phoneBut its Token Security and RLS documentation explicitly says:
OAuth scopes control identity information, not access to database tables or API endpoints.
So this request:
scope=openid emaildoes not mean:
this client can only access email-related database rowsThe access token still represents an authenticated Supabase user.
Database authorization must be handled using Row Level Security and relevant token claims.
That is why the OAuth server should be designed together with RLS, not after it.
OAuth tokens include a __INLINE_CODE_0__ claim
Supabase OAuth access tokens include the OAuth application's __INLINE_CODE_0__.
Conceptually:
{
"sub": "user-uuid",
"role": "authenticated",
"client_id": "partner-app-client-id"
}That lets an RLS policy distinguish:
normal first-party user sessionfrom:
same user acting through Partner App Aor:
same user acting through MCP Client BThis is the building block for client-aware authorization.
Why ordinary user RLS can be too broad for third-party clients
Imagine a normal first-party policy:
create policy "Users can read their projects"
on public.projects
for select
to authenticated
using (
owner_id = (select auth.uid())
);That may be correct for your own trusted app.
But an OAuth token issued to a third-party client also represents the same authenticated user.
If you do nothing else, the third-party application may inherit the same row-level access that your first-party UI has.
That may be more authority than the user thought they were granting.
A better policy can inspect __INLINE_CODE_0__.
For example, conceptually:
create policy "Partner client reads allowed projects"
on public.projects
for select
to authenticated
using (
owner_id = (select auth.uid())
and
(auth.jwt() ->> 'client_id') = 'trusted-partner-client-id'
);Real systems will usually need something richer than one hard-coded client.
The point is:
User identity answers whose data is involved. Client identity answers which application is acting on that user's behalf.
Both can matter.
Do not build a giant __INLINE_CODE_0__ policy
Hard-coding every integration into SQL can become difficult to operate.
A more scalable application might keep an internal registry:
oauth_clients
- client_id
- organisation_id
- status
- trust_level
- integration_typeand separate user grants:
oauth_client_grants
- user_id
- client_id
- permission_set
- granted_at
- revoked_atThen authorization can reason about:
user
+
client
+
tenant
+
permission
+
resourceThe exact schema depends on the product, but the architecture should allow integrations to be disabled, revoked, and audited without rewriting database policies for every partner.
Standard OAuth scopes are not yet custom application permissions
Supabase's current OAuth flow documentation says custom scopes are not currently supported.
Available scopes are centred on OIDC identity data:
- __INLINE_CODE_0__
- __INLINE_CODE_0__
- __INLINE_CODE_0__
- __INLINE_CODE_0__
So you cannot simply invent:
projects:read
projects:write
invoices:readand expect Supabase's current scope system to enforce those database permissions.
Supabase says support for custom scopes is planned for a future release.
Until then, application-specific authorization belongs in your own authorization design, such as RLS, token claims, permission tables, or API-level checks.
This is another reason to avoid promising partners a scope model your platform cannot yet enforce natively.
Custom Access Token Hooks can add client-specific claims
Supabase's current getting-started documentation says Custom Access Token Hooks also run for OAuth token issuance.
That allows the token to be adapted using context such as the OAuth __INLINE_CODE_0__.
Possible uses include:
- setting a meaningful __INLINE_CODE_0__ claim
- adding client-specific metadata
- adding internal permission-set identifiers
- supporting RLS conditions
Conceptually:
OAuth authorization
↓
client_id known
↓
Custom Access Token Hook
↓
Add approved internal claims
↓
Issue JWT
↓
RLS / API validates claimsDo not put unbounded user-controlled data into JWTs.
Claims should describe trusted authorization facts, not become a portable database dump.
Use asymmetric signing keys for OAuth/OIDC
Supabase currently recommends asymmetric JWT signing algorithms such as RS256 or ES256 for OAuth use cases.
Why?
A third-party client can validate a token using your public key from the JWKS endpoint without receiving your signing secret.
The architecture becomes:
Supabase Auth
↓ signs token with private key
Access token
↓
Third-party/resource server
↓
Fetch public key from JWKS
↓
Verify signatureThe current Supabase docs also say that if the __INLINE_CODE_0__ scope is requested, ID-token generation requires asymmetric signing. A project still using HS256 will fail to generate those OIDC ID tokens.
This should be part of the migration checklist before advertising “Sign in with Our App.”
Redirect URIs should be exact
Supabase's OAuth client configuration requires exact redirect URI matches.
Unlike some general Supabase authentication redirect settings, OAuth client redirect URIs do not support wildcard patterns.
That is a security feature.
A sloppy registration like:
https://partner.example/*would create a larger redirect surface if it were allowed.
Prefer separate client registrations for:
development
staging
productionSupabase explicitly recommends separate OAuth clients per environment for stronger isolation and easier secret rotation/auditing.
Public vs confidential OAuth clients
Supabase supports both.
Public client
Examples:
- mobile application
- single-page application
A public client cannot safely store a client secret.
Its token endpoint authentication method is therefore __INLINE_CODE_0__, and PKCE protects the authorization flow.
Confidential client
Examples:
- server-side web application
- backend service with a secure secret store
A confidential client has a client secret and can authenticate to the token endpoint using supported client-secret methods.
Do not embed a confidential-client secret in:
- Flutter
- React Native
- browser JavaScript
- desktop binaries you cannot protect
If the secret ships to users, it is no longer a secret.
How does this work for MCP and AI agents?
The current MCP authorization specification uses OAuth-based discovery and bearer access tokens for protected servers.
The Model Context Protocol authorization specification requires MCP servers to expose protected-resource metadata and requires clients to discover an authorization server using supported OAuth/OIDC mechanisms.
Supabase's MCP guide supports this pattern through its OAuth server.
A clean architecture can look like:
MCP client
↓
Discovers OAuth metadata
↓
Supabase Auth
↓
User sees consent screen
↓
User approves AI tool
↓
OAuth token
↓
MCP server
↓
Business API / Supabase
↓
RLS checks user + clientThe important boundary is:
The AI tool should receive delegated user authority, not your backend's master credential.
That preserves per-user authorization and makes revocation possible.
Dynamic client registration is useful, but expands your attack surface
Supabase supports dynamic client registration for MCP-compatible clients.
That reduces manual onboarding:
new MCP client
→ discovers auth server
→ registers itself
→ starts authorization flowBut “automatic registration” does not mean “automatic trust.”
Supabase's own MCP guidance recommends:
- explicit user approval
- displaying the client name and requested access
- allowing denial
- allowing later revocation
- monitoring registered clients
- validating redirect URIs
For a B2B SaaS with a small set of known integrations, manual client registration may be operationally safer.
For an open developer platform or broad MCP ecosystem, dynamic registration can reduce friction, but should be accompanied by stronger governance and monitoring.
MCP auth is not the same as the hosted Supabase MCP development server
This distinction matters.
Supabase has documentation for its hosted MCP tooling used by developers, and it separately documents how you can build your own MCP server that authenticates your end users through your Supabase OAuth server.
Those are different use cases.
For a production SaaS integration, the architecture is:
Your MCP server
+
Your OAuth server configuration
+
Your user consent
+
Your RLS / API rulesDo not assume that connecting Supabase's own developer MCP server to a project is the production pattern for exposing your customer's business data to arbitrary agents.
What about server-to-server integrations?
Supabase's current OAuth 2.1 server does not support the __INLINE_CODE_0__ grant.
That matters when an integration has no human user.
Example:
Nightly warehouse sync
→ Server A calls Server B
→ No end user is delegating accessThat is not the same problem as:
User authorises Partner App to read their projectsIf your requirement is machine-to-machine authentication, do not force a user-delegated authorization-code flow into it just because the product now has OAuth Server.
Evaluate a proper server credential, service account, signed request, or another suitable machine-auth pattern for the backend.
The authentication mechanism should match the actor.
A practical decision matrix
| Requirement | Supabase OAuth 2.1 Server fit |
|---|---|
| Login for your own Supabase web app | Usually unnecessary |
| Third-party app acts on behalf of a user | Strong fit |
| “Sign in with Your SaaS” | Strong fit |
| MCP/AI client accesses user-authorised data | Strong fit |
| Partner marketplace integrations | Strong fit |
| OIDC identity federation | Potentially strong fit |
| Machine-to-machine job with no user | Current OAuth server flow may not be the right fit |
| Need custom OAuth scopes like __INLINE_CODE_0__ today | Current native scope model is limited |
| Need enterprise provisioning/SCIM lifecycle | OAuth/OIDC alone is incomplete |
| Need a quick shared API key for one trusted internal script | Probably over-engineered |
An architecture for a SaaS integration platform
A production design can separate protocol, consent, authorization and domain access:
Third-party client / MCP client
↓
OAuth discovery + PKCE
↓
Supabase Auth
↓
Your consent UI
↓
OAuth token
↓
API / MCP resource server
↓
Token verification
↓
User + client + tenant authorization
↓
Supabase / application services
↓
Audit eventThe layers have distinct responsibilities.
Supabase Auth
Handles:
- OAuth authorization endpoints
- authorization codes
- PKCE
- access/refresh tokens
- OIDC discovery
- JWKS
Your consent UI
Explains:
- which app is asking
- which identity information is requested
- what application-level access will be granted
- how the user can deny or revoke
Your authorization layer
Decides:
- which clients are trusted
- which tenant the user belongs to
- what data/actions the client may use
- whether a permission has been revoked
- whether sensitive operations need extra approval
RLS / API layer
Enforces the decision on real data.
Audit layer
Records useful events such as:
- client registered
- user consent granted
- consent revoked
- suspicious token/client behaviour
- protected integration action
This makes OAuth a platform capability rather than a decorative login button.
How should multi-tenant SaaS handle OAuth clients?
A multi-tenant system adds another dimension.
A user can belong to:
Organisation A
Organisation Band a third-party integration may be approved for:
Organisation A onlyA token proving the user identity is not enough.
The resource check may need:
user_id
+
client_id
+
organisation_id
+
permissionFor example, an API operation might require:
User belongs to organisation
AND
OAuth client is approved for organisation
AND
Grant includes required app permission
AND
Resource belongs to organisationThis is where OAuth and multi-tenant RLS meet.
If your current RLS only checks:
auth.uid() = owner_idyou may need a more explicit integration authorization model before opening the platform to third-party clients.
For deeper RLS debugging, Softotic's existing guide on Supabase Storage 403 and row-level security covers the broader distinction between request identity, database grants and RLS policy evaluation.
What should you log?
Do not log raw access or refresh tokens.
Do log enough to investigate integration problems.
Useful OAuth audit fields can include:
event
user_id
client_id
organisation_id
authorization_id
grant/consent version
timestamp
result
reason
request correlation IDFor API actions, log the client identity separately from the user.
That allows you to answer:
“Did the user do this through our first-party app or through Partner App X?”
That distinction can be crucial during incident response.
What should you not do?
Do not treat OIDC scopes as database permissions
__INLINE_CODE_0__ and __INLINE_CODE_1__ control identity claims, not access to application tables.
Do not let every OAuth token inherit every first-party RLS permission by accident
Review policies for client-aware access.
Do not expose client secrets in mobile or browser apps
Use public clients with PKCE.
Do not keep HS256 if your OIDC implementation requires ID tokens
Supabase requires asymmetric signing for OIDC ID-token generation.
Do not allow broad redirect URI wildcards
Supabase OAuth clients require exact redirect URIs. Keep that discipline.
Do not enable dynamic registration without governance
Automatic registration is not automatic trust.
Do not give an MCP tool a Supabase secret key when user-delegated OAuth can solve the problem
A project-wide secret bypasses the user-level authorization model.
Do not promise custom OAuth scopes that the current native implementation does not support
Build application permissions separately until your chosen platform capability supports the model you need.
A secure rollout sequence
Phase 1: define the product use case
Write down:
- who the client is
- which user is delegating access
- what the integration needs to do
- whether the client is public/confidential
- whether dynamic registration is needed
- whether the system is multi-tenant
Phase 2: define application permissions
Do this before the consent screen.
Examples:
Read projects
Create tasks
Read invoices
Trigger deployment
Access support ticketsEven if these are not native OAuth scopes, the product needs an explicit permission model.
Phase 3: update authorization/RLS
Ensure the policy can distinguish:
user
client
tenant
permissionwhere appropriate.
Phase 4: configure OAuth/OIDC
- enable OAuth 2.1 Server
- configure authorization path
- migrate to asymmetric signing if required
- register test client
- configure exact redirect URIs
- build consent UI
Phase 5: test security failures
Test:
- wrong redirect URI
- missing/incorrect PKCE verifier
- denied consent
- revoked integration
- wrong tenant
- valid user but disallowed client
- expired access token
- refresh flow
- public client with no secret
- confidential client with wrong secret
- MCP discovery failure
- dynamic registration abuse controls
Phase 6: launch with auditability
Monitor:
- new client registrations
- consent grants/revocations
- token errors
- denied RLS requests
- per-client API volume
- unusual client behaviour
- integration support failures
OAuth becomes operational infrastructure once partners depend on it.
FAQs
Can Supabase act as an OAuth 2.1 provider?
Yes. Supabase Auth can act as an OAuth 2.1 authorization server and OpenID Connect identity provider so third-party applications can authenticate users and receive access/refresh tokens.
Can I build “Sign in with My App” using Supabase?
Yes. Supabase documents “Sign in with Your App” as a core OAuth Server use case. You configure the OAuth server, register clients, and build your own authorization/consent UI while Supabase handles the protocol and token issuance.
Do OAuth scopes control Supabase database access?
No. Supabase's current documentation says the standard OAuth/OIDC scopes control identity data included in tokens/UserInfo, not access to database tables or APIs. Use Row Level Security and application authorization to control data access.
Does Supabase support custom OAuth scopes?
Not currently in the OAuth server documentation reviewed for this article. The current supported scopes are __INLINE_CODE_0__, __INLINE_CODE_1__, __INLINE_CODE_2__, and __INLINE_CODE_3__; Supabase says custom scopes are planned for a future release.
Can Supabase OAuth authenticate MCP clients?
Yes. Supabase documents MCP authentication as a first-class OAuth Server use case, including OAuth discovery, optional dynamic client registration, user consent, token exchange, and RLS-backed access.
Does Supabase OAuth Server support __INLINE_CODE_0__?
No. The current OAuth flow documentation supports authorization code with PKCE and refresh tokens, and says grant types such as __INLINE_CODE_0__ and __INLINE_CODE_1__ are not supported.
Conclusion
Supabase OAuth 2.1 Server is most useful when a Supabase-backed product stops being one application and starts becoming a platform.
The architecture decision is straightforward:
Only our own app needs login
→ ordinary Supabase Auth may be enough
Third-party app needs user-authorised access
→ OAuth Server becomes useful
MCP/AI tool needs user-authorised access
→ OAuth Server + consent + RLS
Partner needs machine-only access
→ evaluate a machine-auth pattern separatelyThe security decision is equally important:
OAuth authenticates the user and client
↓
RLS / application policy authorizes the data and actionsDo not confuse those layers.
A clean OAuth flow with poor RLS can still give an integration too much access.
A perfect RLS policy with a confusing consent screen can still create a bad trust model.
And a powerful MCP agent using a project-wide secret is not delegated authorization at all.
If your SaaS is becoming an integration platform, developer ecosystem, or AI/MCP-enabled product, Softotic's custom software development service can design the platform and authorization architecture, while AI and machine learning development can support agent and MCP workflows that need controlled user-authorised access.