Skip to content

feat: Add optional jwt_issuer option for session token validation - #552

Open
m0tzy wants to merge 2 commits into
mainfrom
devin/1788638893-optional-issuer
Open

feat: Add optional jwt_issuer option for session token validation#552
m0tzy wants to merge 2 commits into
mainfrom
devin/1788638893-optional-issuer

Conversation

@m0tzy

@m0tzy m0tzy commented Sep 5, 2026

Copy link
Copy Markdown

Summary

Lets apps opt in to validating the iss claim of session access tokens. Part of the cross-SDK rollout started in workos/authkit-react-router#83 (see also workos/workos-node#1694, workos/workos-python#725); default behavior is unchanged — no issuer configured means iss is not checked, exactly as before.

  • WorkOS::BaseClient.new(..., jwt_issuer: nil) / config.jwt_issuer — a String or Array<String> of accepted issuers, exposed as client.jwt_issuer. WorkOS.client forwards it from the global configuration.
  • SessionManager#decode_jwt adds iss: client.jwt_issuer, verify_iss: true to the JWT.decode options only when jwt_issuer is non-nil. ruby-jwt's JWT::Claims::Issuer matches against Array(issuers), so a list works natively, and InvalidIssuerError < DecodeError maps to the existing INVALID_JWT reason in Session#authenticate.
  • An explicit empty array fails closed (every token rejected) rather than disabling the check.
  • Following this SDK's convention (README: "The SDK does not read these environment variables automatically"), there is no WORKOS_ISSUER env lookup here; pass ENV["WORKOS_ISSUER"] into config.jwt_issuer yourself if you want that.
WorkOS.configure { |c| c.jwt_issuer = "https://api.workos.com/user_management/#{client_id}" }
# or
WorkOS::Client.new(api_key:, client_id:, jwt_issuer: ["https://api.workos.com", "https://auth.example.com"])

Not touched: lib/workos/client.rb and rbi/** are oagen-generated. Client inherits initialize from the hand-maintained BaseClient, so no generated change is needed for the kwarg; the .rbi signature for BaseClient#initialize / SessionManager#decode_jwt will pick up jwt_issuer on the next regen (CI does not type-check the rbi files).

Tests: standardrb clean; rake test 1251 runs / 0 failures (Ruby 3.4). New cases cover unset, matching, mismatched, missing iss, list, empty list, and WorkOS.configure propagation.

Link to Devin session: https://app.devin.ai/sessions/0ee38e859a9849658a7cdb2d215d89a6
Open in Devin Desktop: https://app.devin.ai/desktop/session/0ee38e859a9849658a7cdb2d215d89a6?variant=devin
Requested by: @m0tzy

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@m0tzy
m0tzy requested review from a team as code owners September 5, 2026 20:08
@m0tzy
m0tzy requested a review from blairworkos September 5, 2026 20:08
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

Original prompt from madison.packer

can we patch this SDK so that the issuer can be either by default (if not passed) or passed a specific issuer?

const issuer = opts.issuer ?? https://${getConfig('apiHostname')}

workos/authkit-react-router#83

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

@greptile-apps

greptile-apps Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds optional issuer validation for session access-token JWTs while preserving existing behavior when no issuer is configured.

  • Exposes jwt_issuer through direct and globally configured clients.
  • Enables ruby-jwt issuer verification for one or multiple accepted issuers.
  • Documents configuration and authentication-failure behavior.
  • Tests matching, mismatched, absent, multiple, empty, and unconfigured issuer cases.

Confidence Score: 5/5

The PR appears safe to merge; no outstanding correctness, security, or repository-rule issues were identified.

Issuer verification is enabled only when explicitly configured, global and direct client paths propagate the option consistently, and the updated test now constructs a token with the iss claim genuinely absent. The previous thread was manually resolved and its underlying coverage issue is fully fixed.

Important Files Changed

Filename Overview
lib/workos/base_client.rb Adds the optional issuer setting to direct client construction and exposes it to service modules.
lib/workos/configuration.rb Adds global issuer configuration and forwards it when constructing the shared client.
lib/workos/session_manager.rb Conditionally enables issuer validation without changing the default JWT-validation behavior.
test/workos/test_session.rb Covers configured and unconfigured issuer behavior, including a genuinely absent issuer claim.
README.md Documents single-issuer and multiple-issuer configuration and the resulting authentication failure reason.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Application configures client] --> B{jwt_issuer configured?}
    B -- No --> C[Verify JWT signature and expiration]
    B -- Yes --> D[Verify signature, expiration, and issuer]
    D --> E{Issuer accepted?}
    E -- Yes --> F[Authenticated session]
    E -- No or missing --> G[INVALID_JWT]
    C --> F
Loading

Reviews (2): Last reviewed commit: "Omit iss claim entirely in missing-issue..." | Re-trigger Greptile

Comment thread test/workos/test_session.rb
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant