Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document the new usptream OAuth 2.0 configuration options #3707

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions crates/handlers/src/upstream_oauth2/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ use minijinja::{
/// Context passed to the attribute mapping template
///
/// The variables available in the template are:
/// - `user`: claims for the user, currently from the ID token. Later, we'll
/// also allow importing from the userinfo endpoint
/// - `user`: claims for the user, merged from the ID token and userinfo
/// endpoint
/// - `id_token_claims`: claims from the ID token
/// - `userinfo_claims`: claims from the userinfo endpoint
/// - `extra_callback_parameters`: extra parameters passed to the callback
#[derive(Debug, Default)]
pub(crate) struct AttributeMappingContext {
Expand Down
39 changes: 37 additions & 2 deletions docs/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,8 @@ upstream_oauth2:
# The issuer URL, which will be used to discover the provider's configuration.
# If discovery is enabled, this *must* exactly match the `issuer` field
# advertised in `<issuer>/.well-known/openid-configuration`.
issuer: https://example.com/
# It must be set if OIDC discovery is enabled (which is the default).
#issuer: https://example.com/

# A human-readable name for the provider,
# which will be displayed on the login page
Expand Down Expand Up @@ -569,8 +570,19 @@ upstream_oauth2:
# - `client_secret_post`
# - `client_secret_jwt`
# - `private_key_jwt` (using the keys defined in the `secrets.keys` section)
# - `sign_in_with_apple` (a special authentication method for Sign-in with Apple)
token_endpoint_auth_method: client_secret_post

# Additional paramaters for the `sign_in_with_apple` authentication method
# See https://www.oauth.com/oauth2-servers/pkce/authorization-code-flow-with-pkce/
#sign_in_with_apple:
# private_key: |
# -----BEGIN PRIVATE KEY-----
# ...
# -----END PRIVATE KEY-----
# team_id: "<team-id>"
# key_id: "<key-id>"

# Which signing algorithm to use to sign the authentication request when using
# the `private_key_jwt` or the `client_secret_jwt` authentication methods
#token_endpoint_auth_signing_alg: RS256
Expand All @@ -595,6 +607,19 @@ upstream_oauth2:
# - `never`: never use PKCE
#pkce_method: auto

# Whether to fetch user claims from the userinfo endpoint
# This is disabled by default, as most providers will return the necessary
# claims in the `id_token`
#fetch_userinfo: true

# If set, ask for a signed response on the userinfo endpoint, and validate
# the response uses the given algorithm
#userinfo_endpoint_auth_signing_alg: RS256

# The userinfo endpoint
# This takes precedence over the discovery mechanism
#userinfo_endpoint: https://example.com/oauth2/userinfo

# The provider authorization endpoint
# This takes precedence over the discovery mechanism
#authorization_endpoint: https://example.com/oauth2/authorize
Expand All @@ -607,6 +632,10 @@ upstream_oauth2:
# This takes precedence over the discovery mechanism
#jwks_uri: https://example.com/oauth2/keys

# Additional parameters to include in the authorization request
#additional_authorization_parameters:
# foo: "bar"

# How user attributes should be mapped
#
# Most of those attributes have two main properties:
Expand All @@ -617,7 +646,8 @@ upstream_oauth2:
# - `require`: always import the attribute, and fail if it's missing
# - `template`: a Jinja2 template used to generate the value. In this template,
# the `user` variable is available, which contains the user's attributes
# retrieved from the `id_token` given by the upstream provider.
# retrieved from the `id_token` given by the upstream provider and/or through
# the userinfo endpoint.
#
# Each attribute has a default template which follows the well-known OIDC claims.
#
Expand Down Expand Up @@ -654,6 +684,11 @@ upstream_oauth2:
# - `always`: mark the email address as verified
# - `never`: mark the email address as not verified
#set_email_verification: import

# An account name, for display purposes only
# This helps end user identify what account they are using
account_name:
#template: "@{{ user.preferred_username }}"
```

## `experimental`
Expand Down
70 changes: 67 additions & 3 deletions docs/setup/sso.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ The authentication service supports importing the following user attributes from
- The localpart/username (e.g. `@localpart:example.com`)
- The display name
- An email address
- An account name, to help end users identify what account they are using

For each of those attributes, administrators can configure a mapping using the claims provided by the upstream provider.
They can also configure what should be done for each of those attributes. It can either:
Expand All @@ -49,12 +50,20 @@ They can also configure what should be done for each of those attributes. It can
- `force`: automatically import the attribute, but don't fail if it is not provided by the provider
- `require`: automatically import the attribute, and fail if it is not provided by the provider

A Jinja2 template is used as mapping for each attribute. The template currently has one `user` variable, which is an object with the claims got through the `id_token` given by the provider.
A Jinja2 template is used as mapping for each attribute.
The following default templates are used:

- `localpart`: `{{ user.preferred_username }}`
- `displayname`: `{{ user.name }}`
- `email`: `{{ user.email }}`
- `account_name`: none

The template has the following variables available:

- `id_token_claims`: an object with the claims got through the `id_token` given by the provider, if provided by the provider
- `userinfo_claims`: an object with the claims got through the `userinfo` endpoint, if `fetch_userinfo` is enabled
- `user`: an object which contains the claims from both the `id_token` and the `userinfo` endpoint
- `extra_callback_parameters`: an object with the additional parameters the provider sent to the redirect URL

## Multiple providers behaviour

Expand Down Expand Up @@ -95,10 +104,14 @@ upstream_oauth2:
# SiWA passes down the user infos as query parameters in the callback
# which is available in the extra_callback_parameters variable
template: |
{%- set user = extra_callback_parameters["user"] | from_json -%}
{{- user.name.firstName }} {{ user.name.lastName -}}
{%- set u = extra_callback_parameters["user"] | from_json -%}
{{- u.name.firstName }} {{ u.name.lastName -}}
email:
action: suggest
account_name:
template: |
{%- set u = extra_callback_parameters["user"] | from_json -%}
{{- u.name.firstName }} {{ u.name.lastName -}}
```

### Authelia
Expand Down Expand Up @@ -230,6 +243,8 @@ upstream_oauth2:
action: suggest
template: "{{ user.email }}"
set_email_verification: always
account_name:
template: "{{ user.name }}"
```


Expand Down Expand Up @@ -261,6 +276,51 @@ upstream_oauth2:
email:
action: suggest
template: "{{ user.email }}"
account_name:
template: "@{{ user.preferred_username }}"
```

### GitHub

GitHub doesn't support OpenID Connect, but it does support OAuth 2.0.
It will use the `fetch_userinfo` option with a manual `userinfo_endpoint` to fetch the user's profile through the GitHub API.

1. Create a [new application](https://github.com/settings/applications/new).
2. Fill in the form with an application name and homepage URL.
3. Use the following Authorization callback URL: `https://<auth-service-domain>/upstream/callback/<id>`
4. Retrieve the Client ID
5. Generate a Client Secret and copy it

Authentication service configuration:

```yaml
upstream_oauth2:
providers:
- id: "01HFS67GJ145HCM9ZASYS9DC3J"
human_name: GitHub
brand_name: github
discovery_mode: disabled
fetch_userinfo: true
token_endpoint_auth_method: "client_secret_post"
client_id: "<client-id>" # TO BE FILLED
client_secret: "<client-secret>" # TO BE FILLED
authorization_endpoint: "https://github.com/login/oauth/authorize"
token_endpoint: "https://github.com/login/oauth/access_token"
userinfo_endpoint: "https://api.github.com/user"
scope: "read:user"
claims_imports:
subject:
template: "{{ userinfo_claims.id }}"
displayname:
action: suggest
template: "{{`{{ userinfo_claims.name }}"
localpart:
action: ignore
email:
action: suggest
template: "{{ userinfo_claims.email }}"
account_name:
template: "@{{ userinfo_claims.login }}"
```


Expand Down Expand Up @@ -291,6 +351,8 @@ upstream_oauth2:
email:
action: suggest
template: "{{ user.email }}"
account_name:
template: "{{ user.email }}"
```


Expand Down Expand Up @@ -384,4 +446,6 @@ upstream_oauth2:
action: suggest
template: "{{ user.email }}"
set_email_verification: always
account_name:
template: "{{ user.preferred_username }}"
```
Loading