-
Notifications
You must be signed in to change notification settings - Fork 34
Add ability to extract custom claims from the JWT during authentication #431
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,9 +30,10 @@ def initialize(user_management:, client_id:, session_data:, cookie_password:) | |
|
|
||
| # Authenticates the user based on the session data | ||
| # @param include_expired [Boolean] If true, returns decoded token data even when expired (default: false) | ||
| # @param block [Proc] Optional block to call to extract additional claims from the decoded JWT | ||
| # @return [Hash] A hash containing the authentication response and a reason if the authentication failed | ||
| # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity | ||
| def authenticate(include_expired: false) | ||
| def authenticate(include_expired: false, &claim_extractor) | ||
| return { authenticated: false, reason: 'NO_SESSION_COOKIE_PROVIDED' } if @session_data.nil? | ||
|
|
||
| begin | ||
|
|
@@ -59,7 +60,7 @@ def authenticate(include_expired: false) | |
| return { authenticated: false, reason: 'INVALID_JWT' } if expired && !include_expired | ||
|
|
||
| # Return full data for valid tokens or when include_expired is true | ||
| { | ||
| result = { | ||
| authenticated: !expired, | ||
| session_id: decoded['sid'], | ||
| organization_id: decoded['org_id'], | ||
|
|
@@ -72,6 +73,8 @@ def authenticate(include_expired: false) | |
| impersonator: session[:impersonator], | ||
| reason: expired ? 'INVALID_JWT' : nil, | ||
| } | ||
| result.merge!(claim_extractor.call(decoded)) if block_given? | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P1] The block’s returned hash can overwrite core fields like A safer pattern is to merge under a dedicated key (e.g. Prompt To Fix With AIThis is a comment left during a code review.
Path: lib/workos/session.rb
Line: 76:76
Comment:
[P1] The block’s returned hash can overwrite core fields like `:authenticated`, `:session_id`, `:organization_id`, and `:reason` because `merge!` prefers the block’s keys. If consumers pass through untrusted logic or make a mistake, this can produce inconsistent or misleading auth results.
A safer pattern is to merge under a dedicated key (e.g. `:custom_claims`) or explicitly reject/ignore collisions with reserved keys.
How can I resolve this? If you propose a fix, please make it concise. |
||
| result | ||
| rescue JWT::DecodeError | ||
| { authenticated: false, reason: 'INVALID_JWT' } | ||
| rescue StandardError => e | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P0]
merge!will raise if the block returns a non-Hash (includingnil), which then gets caught by the genericrescue StandardErrorand turned into{ authenticated: false, reason: e.message }. This makes the new block API brittle and can unexpectedly fail authentication for otherwise-valid sessions if a caller forgets to return a hash.Consider treating
nilas “no extra claims” and validating the return type before merging.Prompt To Fix With AI