Skip to content

Conversation

@dulacp
Copy link

@dulacp dulacp commented Dec 16, 2025

Problem

I noticed there was a TODO for storing the token_endpoint_auth_method value. While integrating with Claude.ai's OAuth flow, we discovered that returning client_secret_basic for all clients (regardless of their actual registration) was breaking the authentication flow. Claude.ai strictly validates the auth method returned during client registration, so it was critical for us to return the correct value.

Per RFC 7591 Section 2:

If unspecified or omitted, the default is "client_secret_basic"

For public clients, the default is none since they don't have a client secret.

Solution

Added proper storage and enforcement of token_endpoint_auth_method:

Database Changes

  • Added token_endpoint_auth_method TEXT column (NOT NULL) to oauth_clients table
  • Migration sets default values for existing clients based on their client_type:
    • confidentialclient_secret_basic
    • publicnone

Behavior

  • New clients get token_endpoint_auth_method persisted during registration
  • Token endpoint validates that the authentication method used matches the registered method
  • Returns the correct token_endpoint_auth_method in client registration responses

@dulacp dulacp requested a review from a team as a code owner December 16, 2025 21:59
Copy link
Contributor

@cemalkilic cemalkilic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @dulacp, thank you for the contribution!

I'll double check if the migration is idempotent

@dulacp dulacp force-pushed the feat/token-endpoint-auth-method-enforcement branch 2 times, most recently from fa3a91b to 9235e2a Compare December 18, 2025 21:40
@cemalkilic
Copy link
Contributor

Hi again @dulacp, sorry for the delay. We’re back to this now. CI is failing on a couple of tests; could you take a look and push a fix when you get a chance? Happy to jump in if you don't.

@dulacp dulacp force-pushed the feat/token-endpoint-auth-method-enforcement branch from 08583ec to 0e65eea Compare January 5, 2026 17:46
@dulacp
Copy link
Author

dulacp commented Jan 5, 2026

Thank @cemalkilic for your message. I found the fix and was able to make the tests pass locally!

@coveralls
Copy link

Pull Request Test Coverage Report for Build 20724067486

Details

  • 38 of 78 (48.72%) changed or added relevant lines in 6 files are covered.
  • 1 unchanged line in 1 file lost coverage.
  • Overall coverage decreased (-0.03%) to 68.754%

Changes Missing Coverage Covered Lines Changed/Added Lines %
internal/api/oauthserver/service.go 17 18 94.44%
internal/api/middleware.go 0 7 0.0%
internal/models/oauth_client.go 12 20 60.0%
internal/api/oauthserver/auth.go 0 24 0.0%
Files with Coverage Reduction New Missed Lines %
internal/api/oauthserver/auth.go 1 0.0%
Totals Coverage Status
Change from base Build 20599680500: -0.03%
Covered Lines: 14767
Relevant Lines: 21478

💛 - Coveralls

@cemalkilic
Copy link
Contributor

Thanks @dulacp ! Tested and confirmed everything is working fine!

One last request (I can't push changes to your fork), can you add the annotation /* auth_migration: 20251216000000 */ for each query? So the file would look like this:

-- Add token_endpoint_auth_method column to oauth_clients table
-- Per RFC 7591: "If unspecified or omitted, the default is 'client_secret_basic'"
-- For public clients, the default is 'none' since they don't have a client secret
/* auth_migration: 20251216000000 */
alter table {{ index .Options "Namespace" }}.oauth_clients
    add column if not exists token_endpoint_auth_method text check (token_endpoint_auth_method in ('client_secret_basic', 'client_secret_post', 'none'));

-- Set default values for existing clients based on their client_type
/* auth_migration: 20251216000000 */
update {{ index .Options "Namespace" }}.oauth_clients
    set token_endpoint_auth_method = case
        when client_type = 'public' then 'none'
        else 'client_secret_basic'
    end
    where token_endpoint_auth_method is null;

-- Now make the column not null
/* auth_migration: 20251216000000 */
alter table {{ index .Options "Namespace" }}.oauth_clients
    alter column token_endpoint_auth_method set not null;

@dulacp
Copy link
Author

dulacp commented Jan 9, 2026

@cemalkilic annotations added 👍, thanks for guiding me through this I wasn't sure how and where to add these.

- Add database migration for token_endpoint_auth_method column (nullable text)
- Store and enforce token_endpoint_auth_method during client registration
- Refactor ExtractClientCredentials to identify which auth method was used
- Add ValidateClientAuthMethod to compare used vs registered method
- Update middleware to enforce auth method matching
- Legacy clients (NULL) remain permissive for backward compatibility
- New clients get strict enforcement per OAuth 2.0 spec

Signed-off-by: Pierre Dulac <[email protected]>
Signed-off-by: Pierre Dulac <[email protected]>
Adjust the indendation and use `slices.Contains` to stay consistent with
the codebase.

Signed-off-by: Pierre Dulac <[email protected]>
Signed-off-by: Pierre Dulac <[email protected]>
@dulacp dulacp force-pushed the feat/token-endpoint-auth-method-enforcement branch from d20d85a to 2f54d9f Compare January 13, 2026 10:25
@dulacp
Copy link
Author

dulacp commented Jan 13, 2026

I've made a rebase on master to fix a small conflict.

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.

3 participants