Merge branch 'quenting/upstream-oauth/better-conflict-options' into quenting/upstream-oauth/skip-interactive

This commit is contained in:
Quentin Gliech
2025-11-28 18:08:09 +01:00
7 changed files with 571 additions and 23 deletions

View File

@@ -2576,14 +2576,24 @@
"description": "How to handle an existing localpart claim",
"oneOf": [
{
"description": "Fails the sso login on conflict",
"description": "Fails the upstream OAuth 2.0 login on conflict",
"type": "string",
"const": "fail"
},
{
"description": "Adds the oauth identity link, regardless of whether there is an existing\n link or not",
"description": "Adds the upstream OAuth 2.0 identity link, regardless of whether there\n is an existing link or not",
"type": "string",
"const": "add"
},
{
"description": "Replace any existing upstream OAuth 2.0 identity link",
"type": "string",
"const": "replace"
},
{
"description": "Adds the upstream OAuth 2.0 identity link *only* if there is no existing\n link for this provider on the matching user",
"type": "string",
"const": "set"
}
]
},

View File

@@ -788,8 +788,10 @@ upstream_oauth2:
# How to handle when localpart already exists.
# Possible values are (default: fail):
# - `add` : Adds the upstream account link to the existing user, regardless of whether there is an existing link or not.
# - `fail` : Fails the upstream OAuth 2.0 login.
# - `add` : Adds the upstream account link to the existing user, regardless of whether there is an existing link or not.
# - `replace` : Replace any existing upstream OAuth 2.0 identity link for this provider on the matching user.
# - `set` : Adds the upstream account link *only* if there is no existing link for this provider on the matching user.
#on_conflict: fail
# The display name is the user's display name.

View File

@@ -69,20 +69,25 @@ The template has the following variables available:
## Allow linking existing user accounts
The authentication service supports linking external provider identities to existing local user accounts.
The authentication service supports linking external provider identities to existing local user accounts if the `localpart` matches.
To enable this behavior, the following option must be explicitly set in the provider configuration:
If the `localpart` given by the upstream provider matches an existing user and the `claims_imports.localpart.action` is set to `force` or `require`, by default the service will refuse to link to that existing account.
This behaviour is controlled by the `claims_imports.localpart.on_conflict` option, which can be set to:
* `fail` *(default)*: fails the upstream OAuth 2.0 login
* `add`: automatically adds the upstream account to the existing user, regardless of whether the existing user already has another upstream account or not
* `set`: automatically adds the upstream account to the existing user only if there are no other upstream accounts for that provider linked to the user
* `replace`: automatically replaces any upstream account for that provider linked to the user
```yaml
claims_imports:
localpart:
on_conflict: add
upstream_oauth2:
providers:
- id:
claims_imports:
localpart:
action: force
on_conflict: set
```
`on_conflict` configuration is specific to `localpart` claim_imports, it can be either:
* `add` : when a user authenticates with the provider for the first time, the system checks whether a local user already exists with a `localpart` matching the attribute mapping `localpart` , _by default `{{ user.preferred_username }}`_. If a match is found, the external identity is linked to the existing local account.
* `fail` *(default)* : fails the sso login.
To enable this option, the `localpart` mapping must be set to either `force` or `require`.
> ⚠️ **Security Notice**
> Enabling this option can introduce a risk of account takeover.