Skip to content

#203: Add kid option for private key authentication - #231

Open
dorner wants to merge 1 commit into
auth0:masterfrom
dorner:203-private-key-kid
Open

#203: Add kid option for private key authentication#231
dorner wants to merge 1 commit into
auth0:masterfrom
dorner:203-private-key-kid

Conversation

@dorner

@dorner dorner commented Aug 12, 2026

Copy link
Copy Markdown

Changes

Adds support for the kid (key ID) JWT header when authenticating with a private key
(client assertion), so that a tenant with two registered credentials can be rotated
deterministically instead of relying on Auth0 picking the right key.

Public API

  • New option: client_assertion_signing_key_id on the :auth0 strategy. When set, it is
    emitted as the kid header of the client assertion JWT. When absent or blank, no kid
    header is sent, just like now.

Classes and methods changed

  • OmniAuth::Auth0::JWTToken#initialize — new optional keyword argument
    client_assertion_signing_key_id:. Added as a keyword to avoid having too many positional arguments.
  • OmniAuth::Auth0::JWTToken#jwt_headers — new private method returning the extra JWT header
    parameters. Passed as the fourth argument to JWT.encode.
  • OmniAuth::Auth0::JWTToken — new client_assertion_signing_key_id reader.
  • OmniAuth::Strategies::Auth0#jwt_token — forwards options.client_assertion_signing_key_id.

No endpoints added, deleted, deprecated, or changed, no UI involved.

Usage

Rails.application.config.middleware.use OmniAuth::Builder do
  provider(
    :auth0,
    AUTH0_CONFIG['auth0_client_id'],
    nil,
    AUTH0_CONFIG['auth0_domain'],
    callback_path: '/auth/auth0/callback',
    client_assertion_signing_key: OpenSSL::PKey::RSA.new(AUTH0_CONFIG[:auth0_client_assertion_signing_key]),
    client_assertion_signing_algorithm: AUTH0_CONFIG[:auth0_client_assertion_signing_algorithm],
    client_assertion_signing_key_id: AUTH0_CONFIG[:auth0_client_assertion_signing_key_id]
  )
end

The value should be the key ID Auth0 assigned to the uploaded public key. README.md has been
updated in both the config/auth0.yml and initializer examples.

References

Testing

The change is three lines of production code. All we care about is that the kid actually
reaches the wire.

Unitspec/omniauth/auth0/jwt_token_spec.rb: asserts the decoded header contains the
configured kid alongside alg, and that the header has no kid key at all when the option is
omitted or set to ''.

Integrationspec/omniauth/strategies/auth0_spec.rb: two new contexts drive a full
callback. One asserts the option is threaded through to JWTToken; the other skips the
JWTToken stub entirely, decodes the real client_assertion sent to POST /oauth/token, and
asserts its kid header. I confirmed both kid assertions fail when the header logic is
disabled, so they are not vacuous.

To verify locally:

bundle exec rake spec

138 examples, 0 failures (133 before this change).

Not tested: whether a live tenant accepts a given kid value. I'll try to install locally and test this way.

  • This change adds unit test coverage
  • This change has been tested on the latest version of the platform/language or why not
    — tested on Ruby 3.2.2, the highest version in this project's CI matrix
    (.github/workflows/matrix.json covers 3.0, 3.1, 3.2)

Checklist

Note that rubocop shows 233 failures on my local using bundle exec rubocop. Not sure why and I didn't want to touch any existing code.

Code written by Claude but fully code reviewed and edited where necessary by myself. Same for the PR description.

@dorner
dorner requested a review from a team as a code owner August 12, 2026 15:59
@dorner

dorner commented Aug 17, 2026

Copy link
Copy Markdown
Author

cc: @rmad17 @kishore7snehil (I'm assuming you guys are the maintainers?)

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.

Support for key ID (kid) in private key authentication

1 participant