Skip to content

fix(auth)!: parse OAuth clients without a name - #1854

Merged
spydon merged 1 commit into
supabase:mainfrom
AndroidPoet:fix/auth-oauth-client-without-name
Sep 18, 2026
Merged

spydon merged 1 commit into
supabase:mainfrom
AndroidPoet:fix/auth-oauth-client-without-name

Conversation

@AndroidPoet

@AndroidPoet AndroidPoet commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Every admin.oauth call that returns a client throws type 'Null' is not a subtype of type 'String' in type cast when the client has no name, because OAuthClient.fromJson casts client_name to a non-nullable String.

A client name is optional in Auth. validateClientName only rejects names over 1024 characters, and the response field is tagged omitempty (internal/api/oauthserver/handlers.go), so a client registered without one comes back with no client_name key at all:

{"client_id": "8f2a1c33-3a1e-4f56-9f0b-2d1d5b8a91c4", "client_type": "public", "token_endpoint_auth_method": "none", "registration_type": "dynamic", "redirect_uris": ["https://example.com/callback"], "grant_types": ["authorization_code"], "response_types": ["code"], "created_at": "2025-01-01T00:00:00Z", "updated_at": "2025-01-01T00:00:00Z"}

clientName is now a String?. The same shape reaches createClient, getClient, updateClient and listClients, and listClients is the worst case, since a single nameless client fails the parse of the whole page.

The sibling type already models it this way: OAuthAuthorizedClient.clientName, which the consent flow parses from the same column, is a String?.

Compatibility

This is breaking against v2, where the field is non-nullable, so MIGRATION.md gets an entry next to the other OAuth ones.

I left CreateOAuthClientOptions.clientName required. The server accepts a registration without a name, so it could be relaxed too, but that is a wider change and nothing forces it: clients you create through the SDK keep their name. Say the word if you want them to match.

Test

test/src/types/oauth_client_test.dart follows the other type tests: one case for a full response, one for a response without client_name. On main the second fails with

type 'Null' is not a subtype of type 'String' in type cast

and passes with the fix.

The admin OAuth suite could not cover this, because CreateOAuthClientOptions cannot express a nameless client, so the parse is tested where it lives.

$ dart format --set-exit-if-changed --line-length 80 <changed files>   # 0 changed
$ dart analyze --fatal-infos lib test                                  # No issues found!
$ dart test test/src/types -j 1                                        # 116 tests, all passed
$ melos analyze                                                        # 25 packages, all clean

I did not run the suites that need a live Auth server this time, since my local stack is down. The analyzer covers those files, so nothing in them stopped compiling, and the change is confined to parsing one field.

Summary by CodeRabbit

  • New Features

    • OAuth client names can now be absent for clients registered without a name.
    • Applications can fall back to the client ID when a client name is unavailable.
  • Documentation

    • Added migration guidance for handling optional OAuth client names.
    • Clarified that clients created through the admin API continue to require a name.
  • Tests

    • Added coverage for OAuth client parsing, including missing client names.

Auth omits `client_name` for a client registered without one, so the
cast in `OAuthClient.fromJson` threw and every `admin.oauth` call that
returns a client failed on the whole response. `clientName` is now a
`String?`, matching `OAuthAuthorizedClient.clientName`, which already
models the same server value that way.
@AndroidPoet
AndroidPoet requested a review from a team as a code owner September 17, 2026 18:32
@coderabbitai

coderabbitai Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 65f8d42a-1708-4b0e-ba8b-a0d2a4c5bcdc

📥 Commits

Reviewing files that changed from the base of the PR and between ef6890b and e01681d.

📒 Files selected for processing (3)
  • MIGRATION.md
  • packages/supabase_auth/lib/src/types/types.dart
  • packages/supabase_auth/test/src/types/oauth_client_test.dart

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.


📝 Walkthrough

Walkthrough

OAuthClient.clientName is now nullable. JSON parsing accepts a missing client_name, tests cover both cases, and the migration guide documents a fallback to clientId.

Changes

OAuth client nullability

Layer / File(s) Summary
Nullable OAuth client model
packages/supabase_auth/lib/src/types/types.dart, packages/supabase_auth/test/src/types/oauth_client_test.dart
OAuthClient.clientName is optional and typed as String?. fromJson accepts a missing client_name. Tests cover complete parsing and a missing client name.
Migration guidance
MIGRATION.md
The guide documents the nullable field, the client.clientName ?? client.clientId fallback, and the continued requirement for CreateOAuthClientOptions.clientName.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: spydon

Merge Risk: ⚪ Minimal · up to e0168

OAuth clients without a name can now be parsed without failing admin OAuth operations, while callers are guided to use the client ID as a fallback. No actionable merge risk remains.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: updating OAuth client parsing to support clients without a name.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

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.

@spydon
spydon merged commit 8d7754c into supabase:main Sep 18, 2026
44 of 45 checks passed
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.

2 participants