Skip to content

feat(networking): implement forward auth#1564

Open
ishanjain28 wants to merge 9 commits into
seerr-team:developfrom
ishanjain28:fw-auth-11
Open

feat(networking): implement forward auth#1564
ishanjain28 wants to merge 9 commits into
seerr-team:developfrom
ishanjain28:fw-auth-11

Conversation

@ishanjain28

@ishanjain28 ishanjain28 commented Apr 6, 2025

Copy link
Copy Markdown
Contributor

Description

This PR adds the Forward Auth feature. It fixes the feedback received in previous attempt here

  1. A few different header names are allowed but they have to added to the allow list in the code. Supporting completely arbitrary headers was difficult.
  2. Forward auth headers are only processed if request came from a trusted proxy and configuring trusted proxy is required to use the forward auth feature.
  3. Forward auth can be done in 3 ways.
    a. Verify the user field against jellyfinUsername | plexUsername columns.
    b. Verify the email field against email column.
    c. Verify both the user and email fields.

How Has This Been Tested?

This has been tested using the included test suite and manually in different environments. Manual test examples,

  1. With Seerr behind 1 trusted proxy and 2 trusted proxies.
  2. With Seerr configured with no trusted proxies
  3. Different header names in use and sometimes they were set, sometimes they were not set and I got the expected result every time.

Screenshots / Logs (if applicable)

Screenshot 2025-04-06 at 17 42 14

Checklist:

  • I have read and followed the contribution guidelines.
  • Disclosed any use of AI (see our policy)
  • I have updated the documentation accordingly.
  • All new and existing tests passed.
  • Successful build pnpm build
  • Translation keys pnpm i18n:extract
  • Database migration (if required)

Summary by CodeRabbit

  • New Features

    • Forward Authentication (SSO) via trusted proxies with configurable user/email headers and Advanced Network Settings UI (trusted IPv4/IPv6 lists, validation).
  • Documentation

    • Added guide for configuring Forward Authentication with Traefik and example auth provider setup.
  • Chores

    • Added runtime IP validation dependency.
  • Tests

    • Updated end-to-end test covering trusted-proxy/forward-auth and restart modal behavior.
  • Quality

    • Centralized server-side auth header handling and allowlist for forwarded headers.

@ishanjain28 ishanjain28 changed the title Fw auth 11 feat: Forward Auth Apr 6, 2025
@ishanjain28

Copy link
Copy Markdown
Contributor Author

@fallenbagel @gauthier-th This PR is now ready for review!

@fallenbagel fallenbagel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I didn't fully review this yet but I noticed one issue. The Dockerfile. Also in terms of UI, I would recommend putting the forwardAuth stuff to be indented like how http(s) proxy is done:
image

Also I would argue that this should be under the advanced networking section as this is not for the normal user. Wdyt about that @gauthier-th

Comment thread Dockerfile
@gauthier-th

Copy link
Copy Markdown
Member

I didn't fully review this yet but I noticed one issue. The Dockerfile. Also in terms of UI, I would recommend putting the forwardAuth stuff to be indented like how http(s) proxy is done:
image

Also I would argue that this should be under the advanced networking section as this is not for the normal user. Wdyt about that @gauthier-th

100% agree

@ishanjain28

Copy link
Copy Markdown
Contributor Author

@fallenbagel @gauthier-th Applied all the suggestions.

  1. reverted changes to dockerfile
  2. Moved the trusted proxies section, forward auth sections to advanced menu. forward auth depends on trusted proxy.
  3. Indented as requested
Screenshot 2025-04-07 at 22 36 49

@ishanjain28 ishanjain28 force-pushed the fw-auth-11 branch 2 times, most recently from a7729d8 to 3c4134f Compare April 7, 2025 17:41
Comment thread src/components/Settings/SettingsNetwork/index.tsx Outdated
Comment thread src/utils/forwardAuthList.ts Outdated
Comment thread server/middleware/auth.ts Outdated
Comment thread src/components/Settings/SettingsNetwork/index.tsx
@github-actions

github-actions Bot commented Apr 8, 2025

Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

@github-actions github-actions Bot removed the merge conflict Cannot merge due to merge conflicts label Apr 8, 2025
@bash9810

Copy link
Copy Markdown

excited for this, would love to setup authentik as the auth for jellyseerr, think this is the way to get that done.

@ishanjain28 ishanjain28 requested a review from fallenbagel April 14, 2025 04:42
@github-actions github-actions Bot added the merge conflict Cannot merge due to merge conflicts label Apr 30, 2025
@github-actions

Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

@github-actions github-actions Bot removed the merge conflict Cannot merge due to merge conflicts label May 21, 2025
@ishanjain28

Copy link
Copy Markdown
Contributor Author

Rebased this PR on top of latest develop and fixed a small bug. Ready for review!

@github-actions github-actions Bot added the merge conflict Cannot merge due to merge conflicts label Jun 13, 2025
@github-actions

Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

@github-actions

Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged.

@exenza

This comment was marked as off-topic.

@ishanjain28

This comment was marked as off-topic.

@exenza

This comment was marked as off-topic.

@gauthier-th gauthier-th requested a review from M0NsTeRRR May 6, 2026 12:07
@Sapd

Sapd commented May 7, 2026

Copy link
Copy Markdown

3 issues:


/api/v1/* returns 401 cookie 'connect.sid' required once forward-auth is on, even when the proxy headers are set correctly.

In OpenAPIValidator: cookieAuth is the security scheme on every endpoint and the validator runs before the auth middleware, so requests without a session cookie get rejected before forward-auth even has a chance.

Fixed like this server/index.ts:

 OpenApiValidator.middleware({
   apiSpec: API_SPEC_PATH,
   validateRequests: true,
+  validateSecurity: false,
 })

isAuthenticated() already does the actual auth check, so the validator's cookie requirement is redundant and it breaks any non-cookie auth path (this PR, OIDC in #2715, future API-key flows). @Jycreyn flagged the
same thing on #2715.


Can we get also automatic user creation?

 if (!user && hasUserHeader && userValue) {
    user = userRepository.create({
      jellyfinUsername: userValue,
      email: emailValue || `${userValue}@forward-auth.local`,
      userType: UserType.JELLYFIN,
      permissions: settings.main.defaultPermissions,
    });
    await userRepository.save(user);
  }

The lookup uses exact SQL equality on jellyfinUsername. That bites in practice because:

  • Jellyfin's AuthenticateByName lowercases the username before storing, so the row is joe
  • Authentik (and most IDPs) preserve original casing in property mappings, so the header arrives as Joe (upper case)

Could the WHERE be case-insensitive? With TypeORM:

  qb.where(
    'LOWER(user.jellyfinUsername) = LOWER(:u) OR LOWER(user.plexUsername) = LOWER(:u)',
    { u: userValue }
  );

Edit: I did fixes here, incl auto creation of users: https://github.com/Sapd/seerr/commits/forward-auth-fixes/

@Xatrekak

Copy link
Copy Markdown

@M0NsTeRRR I have carried forward the work of @ishanjain28 and @Sapd HERE fixing some issues regarding the cloudflare forward auth workflow as well as a bug if the proxy is running a dual stack listener.

If the original author does not return I am willing to put in the work to get this over this finish line whether its fixing any actual issues or just resolving the merge conflicts.

I have end-to-end tested my current branch and it seems fully functional.

@ishanjain28

Copy link
Copy Markdown
Contributor Author

I can take a look at this again on upcoming weekend.

@M0NsTeRRR

M0NsTeRRR commented Jun 11, 2026

Copy link
Copy Markdown
Member

@Xatrekak feel free to open some pull requests on @ishanjain28 fork. That way, he can review your fix and merge it when he has time this weekend.

@github-actions github-actions Bot removed the merge conflict Cannot merge due to merge conflicts label Jun 13, 2026
@ishanjain28

ishanjain28 commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

This has been rebased with changes from @Xatrekak. I also verified it in my instance, it works correctly. Ready for review!

Comment thread server/middleware/auth.ts Dismissed
Comment thread server/middleware/auth.ts Dismissed
@paulo-roger

This comment was marked as off-topic.

@pelaxa

This comment has been minimized.

@SubprimeHardware

Copy link
Copy Markdown

I've been running this branch (the current head, plus fixes) in production behind two proxy paths simultaneously — Cloudflare Access with the email header on one hostname, and a second SSO reverse proxy (Pangolin) that's deliberately not in the trusted list on another. That turned out to be a good stress test, and I'd like to feed back what it found.

Fixes — opened as a PR on the head fork (per the earlier suggestion to route fixes through @ishanjain28): ishanjain28#3. The one reviewers here may care most about: SSR page loads launder forward-auth headers through an unconditionally-trusted loopback (getAuthHeaders forwards them, checkUser trusts 127.0.0.1), so identity headers arriving over untrusted paths are honored on every server-rendered page. In my setup that produced an unescapable //login redirect loop after logout; it's also spoofable in the same direction. Fixed by forwarding the original peer address and evaluating trust against that. The rest: auto-provisioned users were typed after the configured media server (breaking the Plex import's LOCAL→PLEX upgrade path), broken avatars on provisioned users, and nondeterministic matching when the same username exists on different users. Also included, clearly separated and optional: hostname support in Trusted Proxies (docker service names, forward-resolved per request), since compose deployments otherwise have no stable IP to whitelist.

Separately, one bug I hit turned out not to be forward-auth-specific at all (UserContext yanks in-flight navigations back to /login when the auth/me revalidation is aborted) — that's #3231 against develop directly.

One design gap in auto-provisioning worth a maintainer opinion before anyone codes it: the asserted email is both the identity join key and a user-editable profile field. With auto-provision enabled, a user renaming their Seerr email gets a duplicate account on the very next headered request — the IDP still asserts the old address, nothing matches, provisioning fills the gap. (There's no session to cushion it: per-request matching is deliberate here, and correctly so — the earlier session experiment was reverted for real reasons.) Options, roughly in ascending effort:

  • Cheap guard: refuse to provision when an existing user already holds the would-be username (in the rename case the derived username is byte-identical to the original provision's, so this catches it precisely), log a warning instead. Fail-closed, no migration.
  • Proper fix: bind the asserted identity at provision time in dedicated non-user-editable columns, match those ahead of profile email, backfill on first successful match for existing users. Needs a migration, so it should be a deliberate decision on this PR or a follow-up — not something I wanted to unilaterally bolt on.
  • Either way, IDP-side renames remain a documented limitation: header-based auth carries no stable subject claim, so a value join is the best available.

Related, since it came up earlier in this thread: the reverted session-perf idea has a middle path that addresses the Authelia user-switch objection — write the session and record which header identity minted it, then invalidate the session whenever the current header disagrees. Happy to prototype that too if there's interest.

Disclosure: diagnosis and patches were done with AI assistance (Claude); I've reviewed everything and it's all running on my instance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for Forward Auth