Skip to content

feat: Add optional issuer check to SessionManager authenticate - #440

Open
m0tzy wants to merge 1 commit into
mainfrom
devin/1788639144-optional-issuer
Open

feat: Add optional issuer check to SessionManager authenticate#440
m0tzy wants to merge 1 commit into
mainfrom
devin/1788639144-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, workos/workos-ruby#552). Default behavior is unchanged: with no issuer passed, iss is not checked, exactly as before.

SessionManager already takes its session-verification inputs per call (clientId, baseUrl) rather than from client config, so the option follows that shape:

public function authenticate(string $sessionData, string $cookiePassword, string $clientId,
    string $baseUrl = 'https://api.workos.com/',
    string|array|null $issuer = null): array
public function getLogoutUrl(..., string $baseUrl = 'https://api.workos.com/',
    string|array|null $issuer = null): string

decodeAccessToken() gets the same $issuer and, after signature + exp checks, requires $decoded['iss'] to be a string in is_array($issuer) ? $issuer : [$issuer] (strict in_array). A mismatch or missing claim surfaces as the existing ['authenticated' => false, 'reason' => 'invalid_jwt']. An explicit [] fails closed (rejects every token) rather than disabling the check. refresh() does not decode a JWT, so it is untouched.

$workos->sessionManager()->authenticate(
    sessionData: $cookie,
    cookiePassword: $password,
    clientId: $clientId,
    issuer: ["https://api.workos.com/user_management/{$clientId}", 'https://auth.example.com'],
);

Why not a client-level option: WorkOS::__construct and the HttpClient wiring live in generated lib/WorkOS.php (oagen), so a constructor/env option (WORKOS_ISSUER) would need an emitter change upstream; this PR stays inside the hand-maintained SessionManager. The existing finding-#60 TODO about enforcing iss/aud by default is kept and reworded.

Tests: ./script/ci (php-cs-fixer, PHPStan, PHPUnit) passes — 357 tests. New cases cover unset, matching, mismatched, missing iss, list, and empty list.

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:12
@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 to session authentication while preserving existing behavior when no issuer is configured.

  • Accepts either one issuer or a list of permitted issuers.
  • Propagates issuer validation through logout URL generation.
  • Rejects missing, malformed, mismatched, and explicitly disallowed issuer claims as invalid JWTs.
  • Adds focused coverage for disabled, matching, mismatched, missing, multiple, and empty issuer configurations.

Confidence Score: 5/5

The PR appears safe to merge, with the new issuer validation correctly opt-in and fail-closed when configured.

The trailing optional parameters preserve existing callers, issuer claims are checked only after JWT signature and expiration validation, and validation failures remain within the established invalid_jwt error contract.

Important Files Changed

Filename Overview
lib/SessionManager.php Adds backward-compatible, opt-in strict issuer validation to authentication and logout flows.
tests/SessionManagerTest.php Adds comprehensive tests for the supported issuer-validation configurations and failure cases.

Reviews (1): Last reviewed commit: "Add optional issuer check to SessionMana..." | Re-trigger Greptile

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