Skip to content

OIDC link user by iss/sub#977

Open
jmattheis wants to merge 4 commits into
masterfrom
oidc-link-user
Open

OIDC link user by iss/sub#977
jmattheis wants to merge 4 commits into
masterfrom
oidc-link-user

Conversation

@jmattheis

@jmattheis jmattheis commented Jun 14, 2026

Copy link
Copy Markdown
Member

This PR:

  • prevents login in as oidc user if a local user with the same username already exists
    • this can be enabled via a setting
  • identifies oidc user by iss/sub, so even if the username claim changes, they still log into the same account
  • prevents auto registration, if another oidc user with the same username exists
  • adds a oidc e2e test

Sorry for the PR spam @eternal-flame-AD (:.

Issue reported by @KovachVL.

@jmattheis jmattheis requested a review from a team as a code owner June 14, 2026 11:15
@codecov

codecov Bot commented Jun 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.47170% with 13 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (master@3db7dbc). Learn more about missing BASE report.

Files with missing lines Patch % Lines
api/oidc.go 75.00% 7 Missing and 4 partials ⚠️
database/user.go 75.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##             master     #977   +/-   ##
=========================================
  Coverage          ?   74.77%           
=========================================
  Files             ?       67           
  Lines             ?     3354           
  Branches          ?        0           
=========================================
  Hits              ?     2508           
  Misses            ?      662           
  Partials          ?      184           

☔ View full report in Codecov by Harness.
📢 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.

@eternal-flame-AD eternal-flame-AD 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.

Is there no way for an admin to create user for a specific OIDC identity without turning on link by username in general?

I think an alternative implementation that covers more use cases is always make a user for an OIDC identity but make it locked by default - then give admin users a toggle to approve and unlock these users. This is basically what Gitea/Forgejo does with public idP logins.

Comment thread api/oidc.go
Comment thread api/oidc.go
}

func (a *OIDCAPI) registerUser(username, oidcID string) (*model.User, int, error) {
if !a.AutoRegister {

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.

Can we make GOTIFY_REGISTRATION imply this? I can't think of a reason why you want to disable auto register on OIDC but allow general registration.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

A usecase could be if you have linking by username enabled, and don't want oidc users to take over an account, but still allow registrations with local accounts.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

maybe we can combine this in one setting GOTIFY_REGISTRATION=false|oidc|local|true?

@eternal-flame-AD eternal-flame-AD Jun 14, 2026

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.

A usecase could be if you have linking by username enabled, and don't want oidc users to take over an account, but still allow registrations with local accounts.

Isn't this problem already solved by this PR? you can't take over accounts by crossing over registration methods.

maybe we can combine this in one setting GOTIFY_REGISTRATION=false|oidc|local|true

Yeah I would say merge it into one, or call it GOTIFY_REGISTRATION_METHOD=list. The current system is not bad I just prefer config that don't relate to each other despite being in completely different places.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Isn't this problem already solved by this PR? you can't take over accounts by crossing over registration methods.

Nevermind, misunderstood.


The list is a good idea so GOTIFY_REGISTRATION=oidc,local.

Can we make GOTIFY_REGISTRATION imply this? I can't think of a reason why you want to disable auto register on OIDC but allow general registration.

But we want it the other way around, disable general registration, and allow OIDC registration. I think it's valid to allow to configure them separately.

With the current approach, I like that we have a namespace for all oidc related settings. I'd say "showing a registration form" and "automatically creating a user on oidc login" is somewhat different

Now the oidc setting is called autoregister which makes it IMO a little more expressive. E.g.

GOTIFY_OIDC_ENABLED=true
GOTIFY_OIDC_ISSUER=https://auth.example.org
GOTIFY_OIDC_REDIRECTURL=https://gotify.example.org/auth/oidc/callback

GOTIFY_OIDC_AUTOREGISTER=true
# vs
GOTIFY_REGISTRATION=oidc

Maybe we could rename GOTIFY_OIDC_AUTOREGISTER to GOTIFY_OIDC_CREATE_USER to be more explicit.

Comment thread api/oidc.go
@@ -56,6 +56,7 @@ func NewOIDC(conf *config.Configuration, db *database.GormDatabase, userChangeNo
PasswordStrength: conf.PassStrength,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Is there no way for an admin to create user for a specific OIDC identity without turning on link by username in general?

I think an alternative implementation that covers more use cases is always make a user for an OIDC identity but make it locked by default - then give admin users a toggle to approve and unlock these users. This is basically what Gitea/Forgejo does with public idP logins.

Is your usecase for that the admin doesn't want to enable autoregister, and manually whitelists users by either creating them manually or via unlocking?

For me this seems more of an addition than an alternative. The linking is the guard that an oidc user can take over the local account, so this has to be kept regardless, as if you have an local admin user, you probably don't want that a oidc user can take over that account.

I'd see this as extra toggle for autoregister. eg with values false, true, locked. This could be supported also for the normal registration.

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.

For me this seems more of an addition than an alternative. The linking is the guard that an oidc user can take over the local account, so this has to be kept regardless,

That's correct, when I said "alternative" I didn't mean alternative for the whole PR I meant alternative for the quite complicated (and IMO rigid) user linking logic.

I was trying to say while this is a feature not really a bug, this seems like a must have feature for this to work in a real world capacity. In the previous implementation onboarding can simply be done by creating a user with the same username, but now there is no way to actually onboard an OIDC user without turning on auto register in general.

So in practice I am proposing instead of failing outright when autoregister is not opened, register it anyways but lock it by default and say need admin approval.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ahh, you mean the general logic of this, but it's not specific to the change in this PR (as this PR doesn't really removes functionality, it just changes to a safer default).

To summarize, you're use-case is using a public IdP like GitHub where you don't want to enable registrations, and you don't want to link by username.

Can we track this as a separate issue for "User Locking for OIDC/local registration". Are you having this use-case? otherwise I'd probably wait for user feedback on this. I'd say it's very likely when you are self-hosting gotify, that you're also selfhosting the IdP.

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.

Sure, I don't have use case for this personally but I know this is a standard feature on Gitea/Forgejo and a lot of systems in mixed organizations (like universities) are set up this way to whitelist only authorized personnel to certain applications.

@eternal-flame-AD eternal-flame-AD 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.

Apart from the concern of lacking an approval based workflow this looks good to me

@KovachVL if you have time could you double check this?

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.

2 participants