[pull] main from forem:main - #389
Merged
Merged
Conversation
* Add provider-neutral account-switch interstitial Completes the cross-account guard from #23783: the Authenticator already raises AccountSwitchConfirmation when a signed-in user's incoming identity resolves to a different account, but nothing rescued it. Now the callback stages the OmniAuth payload encrypted in the session, renders a confirm/cancel interstitial, and only attaches the identity and swaps the session after explicit confirmation. The Authenticator re-verifies the staged target with expected_user so a target that changed email, became unconfirmed, was suspended, or whose identity was reassigned in the meantime is rejected without mutation. Nothing in this layer knows about a specific provider. Providers that must not hold OAuth credentials beyond the callback request declare `persist_credentials?` false and have them blanked before staging; MLH does so because access is brokered upstream. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Add temporary MLH Core return bridge Everything MLH-Core-specific now lives in two clearly marked places: - Authentication::MlhCoreBridge points the omniauth-mlh strategy at Core (MLH_OAUTH_BASE_URL / MLH_API_BASE_URL), narrows scopes to what Core issues, and disables credential persistence. It carries the removal checklist for the whole bridge. - Authentication::ExternalReturn returns the browser to Core after sign-in. The controller only sees an opaque capture/resolve interface: `capture` turns OmniAuth request params into a session-safe context that rides through the account-switch interstitial, and `resolve` turns it back into a redirect URL. The `continuation` wire format is known only to this class, so swapping in OIDC target_link_uri later touches nothing else. The bridge is inert unless FOREM_EXTERNAL_RETURN_ENABLED=true and an HTTPS FOREM_EXTERNAL_RETURN_URL is configured. The Core-matching seed users only load when the bridge is configured. The earlier after_sign_in_path_for hook is intentionally gone: the callback short-circuits to the return URL before Devise's redirect runs, so the hook only widened the bridge into every password sign-in for no benefit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Pin bullseye-security apt source to snapshot.debian.org Container builds fail in the builder stage's apt install with 404s for bullseye-security packages. Bullseye LTS ended 2026-08-31 and the bullseye-security pool is being purged from deb.debian.org and security.debian.org: their CDN edges return 404 for .deb files the index still lists, and which edge you hit decides whether the build passes. archive.debian.org has not picked the suite up yet. snapshot.debian.org keeps every package permanently, so pin the security source to a snapshot from the last LTS day in the base stage so every derived stage builds again. This is a stopgap until the base image moves to a supported Debian release. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Ben Halpern <bendhalpern@gmail.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* build: pin jwt for delegated authentication * feat: add JWKS-backed delegated-access verifier * Harden delegated access JWKS client and configuration loading - Accept the RFC 7517 JWK Set media type (application/jwk-set+json) as well as application/json, case-insensitively, and advertise both in Accept. An issuer using the registered type previously failed every verification as unavailable. - Add race_condition_ttl to the JWKS cache so that when the cached set expires under load, one caller per process refreshes it while the others keep the just-expired set for a few seconds instead of all hitting the issuer at once, and a single failed refresh no longer fails every concurrent request. - Build the configuration inside to_prepare and drop the hand-written require/require_relative lines so Zeitwerk owns loading of the DelegatedAccess constants. - Raise the same clear ArgumentError for a missing variable as for a blank one, naming the variable. - Document the key-rotation contract implied by the JWKS cache lifetime. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: jcsawyer123 <joshua@jcsawyer.me> Co-authored-by: Ben Halpern <bendhalpern@gmail.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* feat: accept delegated bearer authentication Co-authored-by: Erin Osher <4386583+erinosher@users.noreply.github.com> * Only interpret Bearer tokens when delegated access is enabled API v1 ignored the Authorization header before this feature existed. With the feature disabled (the default on every instance), a request carrying a Bearer header alongside a valid api-key or session was being rejected with 401, which is a regression for any client that sends one. Check the feature flag before looking at the header so disabled instances behave exactly as before; the strict handling is unchanged when the feature is on. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Erin Osher <4386583+erinosher@users.noreply.github.com> Co-authored-by: Ben Halpern <bendhalpern@gmail.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
* docs: document delegated JWKS authentication Co-authored-by: jcsawyer123 <joshua@jcsawyer.me> * Document Bearer auth on every api-key endpoint and the 503 outcome - Make bearer_auth part of the top-level security default alongside api-key, since ApiController accepts a delegated token on every endpoint that accepts an api-key. The eight per-operation overrides are now redundant and removed; public operations keep `security []`. - Document the 503 "delegated access unavailable" response on /api/users/me with a real generated example, and explain in the schema that it applies to every Bearer-capable endpoint. - Note in the docs that the Authorization header is ignored while the feature is disabled, and describe the short refresh grace window on the JWKS cache. - Regenerate swagger/v1/api_v1.json. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: jcsawyer123 <joshua@jcsawyer.me> Co-authored-by: Ben Halpern <bendhalpern@gmail.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 馃挅 Please sponsor : )