Skip to content

fix: admin Authorization header gets overwritten by user token after sign_in_with_password - #1406

Open
AdityaMedidala wants to merge 1 commit into
supabase:mainfrom
AdityaMedidala:fix/admin-auth-header-overwritten-on-signin
Open

AdityaMedidala wants to merge 1 commit into
supabase:mainfrom
AdityaMedidala:fix/admin-auth-header-overwritten-on-signin

Conversation

@AdityaMedidala

Copy link
Copy Markdown

Fixes #1404

What was happening

After calling sign_in_with_password() on a client, any subsequent call to client.auth.admin.create_user() raised "User not allowed" — even when the client was created with a valid service role key.

The root cause: auth.admin was initialised with headers=self._headers, which is the same dict object as auth._headers. So when _listen_to_auth_events updated auth._headers["Authorization"] with the
user's session JWT, admin._headers saw the exact same mutation — because
they were literally the same dict in memory. Admin endpoints then received the user token instead of the service role key, and Supabase correctly rejected the request.

The fix

One line added in __init__ of both _sync/client.py and _async/client.py, before on_auth_state_change is registered:

self.auth.admin._headers = {**self.auth.admin._headers}

This gives admin its own independent copy of the headers dict at construction time, so auth state changes can never bleed into admin headers.

Testing

  • Added test_admin_authorization_header_not_overwritten_on_auth_events to tests/_sync/test_client.py
  • All 15 existing sync tests pass
  • Manually verified against a live Supabase project: admin calls work correctly before sign-in, after sign-in, after sign-out, and across multiple consecutive sign-ins

@coderabbitai

coderabbitai Bot commented Mar 6, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 421f7e49-6b26-42e0-8004-8490dfeed2c9

📥 Commits

Reviewing files that changed from the base of the PR and between 59e3384 and 5dababa.

📒 Files selected for processing (5)
  • quick_check.py
  • src/supabase/src/supabase/_async/client.py
  • src/supabase/src/supabase/_sync/client.py
  • src/supabase/tests/_sync/test_client.py
  • test_bug.py

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Fixed an issue where authorization headers were being improperly overwritten during authentication events, ensuring proper authentication integrity in the Python SDK.
  • Tests

    • Added regression test to verify authorization headers remain intact during authentication state changes.

Walkthrough

The pull request fixes a regression in the authentication module where the admin authorization header was being overwritten by user session tokens during authentication events. The fix ensures that when a user signs in, the admin headers are explicitly maintained to use the service role key (supabase_key). Changes are applied to both sync and async client implementations, with a regression test added to prevent future occurrences.

Assessment against linked issues

Objective Addressed Explanation
Prevent admin authorization header from being overwritten by user session tokens during auth events [#1404] ✅
Ensure admin.create_user() uses correct service role key authorization [#1404] ✅
Add regression test to verify admin headers are not overwritten [#1404] ✅

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@AdityaMedidala

Copy link
Copy Markdown
Author

Hey @leoortizz and @rylena tagging you as recent contributors to this file. This fixes #1404 . Happy to adjust anything if the approach doesn't fit the project direction. Thanks

@rylena

rylena commented Mar 8, 2026

Copy link
Copy Markdown
Contributor

Hey @leoortizz and @rylena tagging you as recent contributors to this file. This fixes #1404 . Happy to adjust anything if the approach doesn't fit the project direction. Thanks

(#1406) appears to directly fix issue #1404 (#1404):

So the PR looks good to me 👍🏾

@Eklavya2106

Copy link
Copy Markdown

Hi, I’d like to work on this issue. Is it still open

@grdsdev

grdsdev commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Thanks for this @AdityaMedidala, and sorry it sat for so long. The bug is real and your diagnosis was right. I reproduced it against a local Supabase instance before touching anything:

admin.list_users() before sign-in : OK
admin.list_users() after  sign-in : AuthApiError: User not allowed
admin/_client share one dict      : True

I also confirmed your patch fixes it end to end.

I've opened #1645 with the same fix moved one layer down, into GoTrueBaseAPI.__init__:

- self._headers = headers
+ self._headers = dict(headers)

The reason: the aliasing is created inside supabase_auth, not in the wrapper. GoTrueClient.__init__ passes its own _headers to the admin API, so client._headers is client.admin._headers for anyone using supabase_auth directly, not just users going through the supabase client. Copying on the way in covers those callers too, needs no wrapper changes, and keeps future in-place header writes safe.

Three smaller things I found while reviewing this branch, in case they're useful to you generally:

  • quick_check.py and test_bug.py are committed at the repo root (both empty). test_bug.py matches pytest's collection pattern.
  • The regression test is in tests/_sync/test_client.py only. This repo generates _sync from _async via unasync, so the next make supabase.build-sync would have silently deleted it. Tests need to go in tests/_async/ and be generated down.
  • The branch isn't ruff format clean (one 94-char line). make ruff sorts it.

I'm leaving this open rather than closing it — that's the maintainers' call, and #1645 links back here. Your finding is credited in that PR.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

admin.create_user returns "User not allowed" in v2.28.0 but works in v2.11.0

4 participants