Skip to content

feat: custom oauth2 provider#2006

Open
alexma233 wants to merge 10 commits intoumputun:masterfrom
alexma233:feat/custom-oauth2-provider
Open

feat: custom oauth2 provider#2006
alexma233 wants to merge 10 commits intoumputun:masterfrom
alexma233:feat/custom-oauth2-provider

Conversation

@alexma233
Copy link
Copy Markdown

Custom OAuth2 integration on both frontend and backend.

@alexma233 alexma233 requested a review from umputun as a code owner February 15, 2026 13:54
Copy link
Copy Markdown
Collaborator

@paskal paskal left a comment

Choose a reason for hiding this comment

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

Thanks a ton! Tested this with GitHub OAuth endpoints on a live instance — works as expected. A few things:

  1. built-in provider names aren't reserved (server.go:1023). only email and anonymous are blocked, but AUTH_CUSTOM_NAME=github or AUTH_CUSTOM_NAME=telegram would silently register a competing route. should add the full list: google, github, facebook, yandex, microsoft, patreon, discord, telegram, dev, apple. docs have the same gap — says "should not be email or anonymous" but doesn't mention built-in provider names.

  2. user ID hashing uses SHA-256 (server.go:1043) while all built-in providers use SHA-1. no comment explaining the choice. if intentional, add a note — otherwise it'll confuse anyone who switches from custom to a native provider later (IDs won't match, existing comments become disassociated).

  3. no happy-path test — only the partial-config error case is covered. worth adding a test that registers a fully configured custom provider and checks it appears in the provider list, similar to TestServerApp_DevMode.

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 62.07%. Comparing base (06436ff) to head (2d23cb4).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2006      +/-   ##
==========================================
+ Coverage   62.03%   62.07%   +0.03%     
==========================================
  Files         132      132              
  Lines        3037     3040       +3     
  Branches      788      791       +3     
==========================================
+ Hits         1884     1887       +3     
  Misses       1039     1039              
  Partials      114      114              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@janikvonrotz
Copy link
Copy Markdown
Contributor

I was just checking the docs and was looking for this feature. I would like to authenticate users with Codeberg (Foregejo).

I'll try to test a custom provider with https://remark42.com/docs/contributing/backend/ ...

@alexma233 alexma233 requested a review from paskal February 23, 2026 10:38
@alexma233
Copy link
Copy Markdown
Author

@paskal

I’ve addressed the review feedback:

  • reserved all built-in provider names
  • added a happy-path test
  • aligned hashing with built-in providers (SHA-1, with explicit comment + nolint)

Could you please take another look when you have time? Thanks!

@paskal paskal added the backend label Mar 25, 2026
paskal
paskal previously approved these changes Mar 26, 2026
Copy link
Copy Markdown
Owner

@umputun umputun left a comment

Choose a reason for hiding this comment

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

nice feature, looks solid overall. few things I noticed:

  1. "twitter" is missing from reservedCustomProviderNames (server.go:505). it's still registered as a provider at line 1019, so AUTH_CUSTOM_NAME=twitter would create a route conflict

  2. custom provider name isn't validated for URL-safe characters (server.go:1038). it gets used directly in route paths (/auth/<name>/login), so names with spaces or special chars would break routing. docs say "must be URL-safe" but code doesn't enforce it - a simple regex like ^[a-z0-9][a-z0-9_-]*$ would close the gap

  3. if all user info fields (ID, email, name) come back empty from the provider, sourceID is "" and all such users hash to the same ID (server.go:1050-1057). worth at least logging a warning

  4. docs don't mention only one custom provider is supported. users might expect to configure multiple

@alexma233
Copy link
Copy Markdown
Author

@umputun thanks, addressed all four points:

  • added twitter to reserved custom provider names
  • validate AUTH_CUSTOM_NAME in code with ^[a-z0-9][a-z0-9_-]*$
  • improved custom user ID fallback to avoid hashing an empty identifier; it now falls back through configured fields and logs a warning when no stable identity fields are returned
  • updated docs to clarify that only one custom OAuth2 provider is supported at the moment

Please take another look when you have a chance.

@paskal
Copy link
Copy Markdown
Collaborator

paskal commented Mar 27, 2026

I am thinking that adding just one doesn't make much sense, adding more would be better. Three approaches from top of my mind:

Option A: Fixed numbered slots (recommended)

Custom1 CustomAuthGroup `group:"custom1" namespace:"custom1" env-namespace:"CUSTOM1"`
Custom2 CustomAuthGroup `group:"custom2" namespace:"custom2" env-namespace:"CUSTOM2"`
Custom3 CustomAuthGroup `group:"custom3" namespace:"custom3" env-namespace:"CUSTOM3"`

Env vars: AUTH_CUSTOM1_NAME=oidc, AUTH_CUSTOM2_NAME=codeberg, etc.

  • Pros: works with go-flags out of the box, zero custom parsing, familiar pattern (Traefik does something similar)
  • Cons: hard cap on N providers (3–5 is plenty for real use), minor struct bloat
  • Effort: small — loop over a slice of []*CustomAuthGroup in addAuthProviders

Option B: Manual env scanning
Scan os.Environ() for AUTH_CUSTOM_<N>_* prefixes, group by index, parse into structs manually.

  • Pros: unlimited providers
  • Cons: bypasses go-flags entirely for this section, more code, needs its own validation/help-text
  • Effort: medium

Option C: JSON in a single env var
AUTH_CUSTOM_PROVIDERS='[{"name":"oidc","cid":"...","csec":"...","auth_url":"..."}]'

  • Pros: unlimited providers, single env var
  • Cons: JSON-in-env-var is awkward for docker-compose users, doesn't show up in --help, error messages are less clear
  • Effort: small-medium

I'll think more about it after the merge and before we cut v1.16.0. Would love to hear your thoughts on that too, Alex.

@alexma233
Copy link
Copy Markdown
Author

I am thinking that adding just one doesn't make much sense, adding more would be better. Three approaches from top of my mind:

...

Thanks, that makes sense. I agree multiple custom providers would be better long-term.

For this PR, I’d still prefer to keep the scope to a single custom provider and get the minimal version merged first. It already solves the main integration use case with a small, easy-to-review change set.

If we add multi-provider support next, I’d lean toward Option A. It fits Remark42’s existing go-flags/env style best, keeps help text and validation straightforward, and is much friendlier for docker-compose users than JSON-in-env or manual env parsing.

So my vote would be: merge this one as-is, then do multi-provider support in a follow-up PR.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants