Open
Conversation
81a3514 to
36dfcd9
Compare
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Fizzy × Forward Auth (Stargate) Integration Plan
Goal
When a request is authenticated by Stargate (or a similar Forward Auth gateway), the gateway injects these headers:
X-Auth-Email— Authenticated user email (required)X-Auth-User— Gateway-side user identifier (optional; for logging or default display name)X-Auth-Amr,X-Forwarded-For,X-Real-Ip, etc. — Optional, for auditing or IP loggingFizzy only trusts these headers when the request comes from a trusted source, then uses them for identity resolution and authorization, without requiring magic-link login.
Architecture and Data Flow
resume_sessionandauthenticate_by_bearer_token, addauthenticate_by_forward_auth; if all three fail, thenrequest_authentication(redirect to login).Implementation Details
1. Auth chain extension
app/controllers/concerns/authentication.rbrequire_authenticationfromresume_session || authenticate_by_bearer_token || request_authenticationto
resume_session || authenticate_by_bearer_token || authenticate_by_forward_auth || request_authenticationand add a private method
authenticate_by_forward_auth.Logic summary:
false(do not set identity).request.headers["X-Auth-Email"], normalize (strip, downcase), then find or createIdentity(aligned with existing Identity normalization).Current.accountis set (from URL viaconfig/initializers/tenanting/account_slug.rb):Userfor this Identity in that Account.member; name from email local part orX-Auth-User).request_authentication).Current.identity = identity.start_new_session_for(identity)to create a Fizzy session and set a cookie, so ActionCable and page reloads still identify the user via cookie. If no session is created, every request must carry Forward Auth headers and ActionCable would need separate support (see below).2. Trust and security
Requests must be trusted only when they actually come from our gateway; otherwise anyone could forge
X-Auth-Emailand impersonate users.Option 1 (recommended): Trust by source IP
Run Forward Auth auth only when
request.remote_ipis in a configured trusted IP list (e.g. Traefik/Stargate internal network or127.0.0.1). Fizzy already hasconfig/initializers/true_client_ip.rbforTrue-Client-IP→X-Forwarded-For; the effective IP is resolved by RailsRemoteIpetc., so userequest.remote_ipfor the trust check, consistent with existing auditing.Option 2 (optional): Secret header from gateway
If Stargate or Traefik sets a custom header after auth (e.g.
X-Forward-Auth-Verified: <shared_secret>), Fizzy can verify that header against a configured secret before trustingX-Auth-Email. Can be used instead of or in addition to the IP allowlist.Implement a “Forward Auth config” object that exposes
trusted?(request)(check IP and/or secret header). Proceed withauthenticate_by_forward_authonly whentrusted?(request)is true and the auth header is present.3. Configuration
config/initializers/forward_auth.rb(or inconfig/application.rb’sto_prepare), reading from ENV orRails.application.config.FORWARD_AUTH_ENABLED— Enable Forward Auth (e.g.true/1).FORWARD_AUTH_TRUSTED_IPS— Comma-separated trusted IPs or CIDRs (e.g.127.0.0.1,10.0.0.0/8); if empty, rely only on secret header when used.FORWARD_AUTH_SECRET_HEADER,FORWARD_AUTH_SECRET— Optional: header name and expected value set by the gateway for verification.FORWARD_AUTH_AUTO_PROVISION— When Identity exists but there is no User in the current Account, auto-create User (e.g.true).FORWARD_AUTH_DEFAULT_ROLE— Default role for auto-created Users (e.g.member).FORWARD_AUTH_CREATE_SESSION— Create Fizzy session and set cookie on first successful Forward Auth (recommendedtruefor WebSocket compatibility).Expose this as
Rails.application.config.forward_author a config singleton, and use it inauthenticate_by_forward_authand trust logic.4. Identity / User and header mapping
X-Auth-Email, aligned withemail_addressformat and uniqueness inapp/models/identity.rb. Look up withIdentity.find_by(email_address: normalized_email); usefind_or_create_bywhen auto-creation is enabled (and keep alignment with existingnormalizes :email_address).index_users_on_account_id_and_identity_id). WithFORWARD_AUTH_AUTO_PROVISION, follow the pattern indb/seeds.rb’sfind_or_create_userto create Users, setverified_at: Time.currentand default role; name from email local part or a friendly value fromX-Auth-User.5. ActionCable (WebSocket)
app/channels/application_cable/connection.rbresolves the session only viacookies.signed[:session_token], then derivescurrent_user.set_current_user: when there is no valid session in the cookie, if the request has trusted Forward Auth headers (or a token set by the gateway), use the same trust and Identity/User resolution to setcurrent_user. That requires WebSocket requests to go through the same gateway with the same headers (or optional token). Prefer the “create session” approach to limit scope of changes.6. Testing and documentation
test/controllers/concerns/or existing controller tests, add cases where Forward Auth is enabled, request is trusted, and a validX-Auth-Emailcorrectly setsCurrent.identity/Current.user.docs/or in the README on using Fizzy with Stargate or other Forward Auth gateways (how to enable, trust config, required headers, optional auto-provision and session strategy), and reference the Stargate repo (e.g. https://github.com/soulteary/stargate).7. Compatibility with existing behavior
FORWARD_AUTH_ENABLEDis unset or the request fails the trust check, behavior is unchanged (Cookie session + Bearer + magic link only).authenticate_by_forward_authbecauseresume_sessionorauthenticate_by_bearer_tokenreturns true first.Current.accountset) and authentication is required.Suggested implementation order
authenticate_by_forward_authinapp/controllers/concerns/authentication.rb(Identity/User lookup, optional auto-provision, optional session creation) and wire it intorequire_authentication.Risks and notes
0.0.0.0/0or leaking the secret) allows arbitrary user impersonation; review before deployment.