Configuring Synapse to authenticate against an OpenID Connect provider
-Synapse can be configured to use an OpenID Connect Provider (OP) for -authentication, instead of its own local password database.
-Any OP should work with Synapse, as long as it supports the authorization code -flow. There are a few options for that:
--
-
-
-
start a local OP. Synapse has been tested with Hydra and -Dex. Note that for an OP to work, it should be served under a -secure (HTTPS) origin. A certificate signed with a self-signed, locally -trusted CA should work. In that case, start Synapse with a
-SSL_CERT_FILE
-environment variable set to the path of the CA.
- -
-
set up a SaaS OP, like Google, Auth0 or -Okta. Synapse has been tested with Auth0 and Google.
-
-
It may also be possible to use other OAuth2 providers which provide the -authorization code grant type, -such as Github.
-Preparing Synapse
-The OpenID integration in Synapse uses the
-authlib
library, which must be installed
-as follows:
-
-
-
-
The relevant libraries are included in the Docker images and Debian packages -provided by
-matrix.org
so no further action is needed.
- -
-
If you installed Synapse into a virtualenv, run
-/path/to/env/bin/pip install matrix-synapse[oidc]
to install the necessary dependencies.
- -
-
For other installation mechanisms, see the documentation provided by the -maintainer.
-
-
To enable the OpenID integration, you should then add a section to the oidc_providers
-setting in your configuration file (or uncomment one of the existing examples).
-See sample_config.yaml for some sample settings, as well as
-the text below for example configurations for specific providers.
Sample configs
-Here are a few configs for providers that should work with Synapse.
-Microsoft Azure Active Directory
-Azure AD can act as an OpenID Connect Provider. Register a new application under
-App registrations in the Azure AD management console. The RedirectURI for your
-application should point to your matrix server:
-[synapse public baseurl]/_synapse/client/oidc/callback
Go to Certificates & secrets and register a new client secret. Make note of your
-Directory (tenant) ID as it will be used in the Azure links.
-Edit your Synapse config file and change the oidc_config
section:
oidc_providers:
- - idp_id: microsoft
- idp_name: Microsoft
- issuer: "https://login.microsoftonline.com/<tenant id>/v2.0"
- client_id: "<client id>"
- client_secret: "<client secret>"
- scopes: ["openid", "profile"]
- authorization_endpoint: "https://login.microsoftonline.com/<tenant id>/oauth2/v2.0/authorize"
- token_endpoint: "https://login.microsoftonline.com/<tenant id>/oauth2/v2.0/token"
- userinfo_endpoint: "https://graph.microsoft.com/oidc/userinfo"
-
- user_mapping_provider:
- config:
- localpart_template: "{{ user.preferred_username.split('@')[0] }}"
- display_name_template: "{{ user.name }}"
-
-Dex
-Dex is a simple, open-source, certified OpenID Connect Provider. -Although it is designed to help building a full-blown provider with an -external database, it can be configured with static passwords in a config file.
-Follow the Getting Started guide -to install Dex.
-Edit examples/config-dev.yaml
config file from the Dex repo to add a client:
staticClients:
-- id: synapse
- secret: secret
- redirectURIs:
- - '[synapse public baseurl]/_synapse/client/oidc/callback'
- name: 'Synapse'
-
-Run with dex serve examples/config-dev.yaml
.
Synapse config:
-oidc_providers:
- - idp_id: dex
- idp_name: "My Dex server"
- skip_verification: true # This is needed as Dex is served on an insecure endpoint
- issuer: "http://127.0.0.1:5556/dex"
- client_id: "synapse"
- client_secret: "secret"
- scopes: ["openid", "profile"]
- user_mapping_provider:
- config:
- localpart_template: "{{ user.name }}"
- display_name_template: "{{ user.name|capitalize }}"
-
-Keycloak
-Keycloak is an opensource IdP maintained by Red Hat.
-Follow the Getting Started Guide to install Keycloak and set up a realm.
--
-
-
-
Click
-Clients
in the sidebar and clickCreate
- -
-
Fill in the fields as below:
-
-
Field | Value |
---|---|
Client ID | synapse |
Client Protocol | openid-connect |
-
-
- Click
Save
- - Fill in the fields as below: -
Field | Value |
---|---|
Client ID | synapse |
Enabled | On |
Client Protocol | openid-connect |
Access Type | confidential |
Valid Redirect URIs | [synapse public baseurl]/_synapse/client/oidc/callback |
-
-
- Click
Save
- - On the Credentials tab, update the fields: -
Field | Value |
---|---|
Client Authenticator | Client ID and Secret |
-
-
- Click
Regenerate Secret
- - Copy Secret -
oidc_providers:
- - idp_id: keycloak
- idp_name: "My KeyCloak server"
- issuer: "https://127.0.0.1:8443/auth/realms/{realm_name}"
- client_id: "synapse"
- client_secret: "copy secret generated from above"
- scopes: ["openid", "profile"]
- user_mapping_provider:
- config:
- localpart_template: "{{ user.preferred_username }}"
- display_name_template: "{{ user.name }}"
-
-Auth0
-Auth0 is a hosted SaaS IdP solution.
--
-
-
-
Create a regular web application for Synapse
-
- -
-
Set the Allowed Callback URLs to
-[synapse public baseurl]/_synapse/client/oidc/callback
- -
-
Add a rule to add the
-preferred_username
claim.-Code sample
-
-function addPersistenceAttribute(user, context, callback) { - user.user_metadata = user.user_metadata || {}; - user.user_metadata.preferred_username = user.user_metadata.preferred_username || user.user_id; - context.idToken.preferred_username = user.user_metadata.preferred_username; - - auth0.users.updateUserMetadata(user.user_id, user.user_metadata) - .then(function(){ - callback(null, user, context); - }) - .catch(function(err){ - callback(err); - }); -} -
-
Synapse config:
-oidc_providers:
- - idp_id: auth0
- idp_name: Auth0
- issuer: "https://your-tier.eu.auth0.com/" # TO BE FILLED
- client_id: "your-client-id" # TO BE FILLED
- client_secret: "your-client-secret" # TO BE FILLED
- scopes: ["openid", "profile"]
- user_mapping_provider:
- config:
- localpart_template: "{{ user.preferred_username }}"
- display_name_template: "{{ user.name }}"
-
-GitHub
-GitHub is a bit special as it is not an OpenID Connect compliant provider, but -just a regular OAuth2 provider.
-The /user
API endpoint
-can be used to retrieve information on the authenticated user. As the Synapse
-login mechanism needs an attribute to uniquely identify users, and that endpoint
-does not return a sub
property, an alternative subject_claim
has to be set.
-
-
- Create a new OAuth application: https://github.com/settings/applications/new. -
- Set the callback URL to
[synapse public baseurl]/_synapse/client/oidc/callback
.
-
Synapse config:
-oidc_providers:
- - idp_id: github
- idp_name: Github
- idp_brand: "github" # optional: styling hint for clients
- discover: false
- issuer: "https://github.com/"
- client_id: "your-client-id" # TO BE FILLED
- client_secret: "your-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"
- scopes: ["read:user"]
- user_mapping_provider:
- config:
- subject_claim: "id"
- localpart_template: "{{ user.login }}"
- display_name_template: "{{ user.name }}"
-
-Google is an OpenID certified authentication and authorisation provider.
--
-
- Set up a project in the Google API Console (see -https://developers.google.com/identity/protocols/oauth2/openid-connect#appsetup). -
- Add an "OAuth Client ID" for a Web Application under "Credentials". -
- Copy the Client ID and Client Secret, and add the following to your synapse config:
-
-oidc_providers: - - idp_id: google - idp_name: Google - idp_brand: "google" # optional: styling hint for clients - issuer: "https://accounts.google.com/" - client_id: "your-client-id" # TO BE FILLED - client_secret: "your-client-secret" # TO BE FILLED - scopes: ["openid", "profile"] - user_mapping_provider: - config: - localpart_template: "{{ user.given_name|lower }}" - display_name_template: "{{ user.name }}" -
- - Back in the Google console, add this Authorized redirect URI:
[synapse public baseurl]/_synapse/client/oidc/callback
.
-
Twitch
--
-
- Setup a developer account on Twitch -
- Obtain the OAuth 2.0 credentials by creating an app -
- Add this OAuth Redirect URL:
[synapse public baseurl]/_synapse/client/oidc/callback
-
Synapse config:
-oidc_providers:
- - idp_id: twitch
- idp_name: Twitch
- issuer: "https://id.twitch.tv/oauth2/"
- client_id: "your-client-id" # TO BE FILLED
- client_secret: "your-client-secret" # TO BE FILLED
- client_auth_method: "client_secret_post"
- user_mapping_provider:
- config:
- localpart_template: "{{ user.preferred_username }}"
- display_name_template: "{{ user.name }}"
-
-GitLab
--
-
- Create a new application. -
- Add the
read_user
andopenid
scopes.
- - Add this Callback URL:
[synapse public baseurl]/_synapse/client/oidc/callback
-
Synapse config:
-oidc_providers:
- - idp_id: gitlab
- idp_name: Gitlab
- idp_brand: "gitlab" # optional: styling hint for clients
- issuer: "https://gitlab.com/"
- client_id: "your-client-id" # TO BE FILLED
- client_secret: "your-client-secret" # TO BE FILLED
- client_auth_method: "client_secret_post"
- scopes: ["openid", "read_user"]
- user_profile_method: "userinfo_endpoint"
- user_mapping_provider:
- config:
- localpart_template: '{{ user.nickname }}'
- display_name_template: '{{ user.name }}'
-
-Like Github, Facebook provide a custom OAuth2 API rather than an OIDC-compliant -one so requires a little more configuration.
--
-
- You will need a Facebook developer account. You can register for one -here. -
- On the apps page of the developer -console, "Create App", and choose "Build Connected Experiences". -
- Once the app is created, add "Facebook Login" and choose "Web". You don't -need to go through the whole form here. -
- In the left-hand menu, open "Products"/"Facebook Login"/"Settings".
-
-
-
- Add
[synapse public baseurl]/_synapse/client/oidc/callback
as an OAuth Redirect -URL.
-
- - Add
- In the left-hand menu, open "Settings/Basic". Here you can copy the "App ID" -and "App Secret" for use below. -
Synapse config:
- - idp_id: facebook
- idp_name: Facebook
- idp_brand: "facebook" # optional: styling hint for clients
- discover: false
- issuer: "https://facebook.com"
- client_id: "your-client-id" # TO BE FILLED
- client_secret: "your-client-secret" # TO BE FILLED
- scopes: ["openid", "email"]
- authorization_endpoint: https://facebook.com/dialog/oauth
- token_endpoint: https://graph.facebook.com/v9.0/oauth/access_token
- user_profile_method: "userinfo_endpoint"
- userinfo_endpoint: "https://graph.facebook.com/v9.0/me?fields=id,name,email,picture"
- user_mapping_provider:
- config:
- subject_claim: "id"
- display_name_template: "{{ user.name }}"
-
-Relevant documents:
--
-
- https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow -
- Using Facebook's Graph API: https://developers.facebook.com/docs/graph-api/using-graph-api/ -
- Reference to the User endpoint: https://developers.facebook.com/docs/graph-api/reference/user -
Gitea
-Gitea is, like Github, not an OpenID provider, but just an OAuth2 provider.
-The /user
API endpoint
-can be used to retrieve information on the authenticated user. As the Synapse
-login mechanism needs an attribute to uniquely identify users, and that endpoint
-does not return a sub
property, an alternative subject_claim
has to be set.
-
-
- Create a new application. -
- Add this Callback URL:
[synapse public baseurl]/_synapse/client/oidc/callback
-
Synapse config:
-oidc_providers:
- - idp_id: gitea
- idp_name: Gitea
- discover: false
- issuer: "https://your-gitea.com/"
- client_id: "your-client-id" # TO BE FILLED
- client_secret: "your-client-secret" # TO BE FILLED
- client_auth_method: client_secret_post
- scopes: [] # Gitea doesn't support Scopes
- authorization_endpoint: "https://your-gitea.com/login/oauth/authorize"
- token_endpoint: "https://your-gitea.com/login/oauth/access_token"
- userinfo_endpoint: "https://your-gitea.com/api/v1/user"
- user_mapping_provider:
- config:
- subject_claim: "id"
- localpart_template: "{{ user.login }}"
- display_name_template: "{{ user.full_name }}"
-
-XWiki
-Install OpenID Connect Provider extension in your XWiki instance.
-Synapse config:
-oidc_providers:
- - idp_id: xwiki
- idp_name: "XWiki"
- issuer: "https://myxwikihost/xwiki/oidc/"
- client_id: "your-client-id" # TO BE FILLED
- client_auth_method: none
- scopes: ["openid", "profile"]
- user_profile_method: "userinfo_endpoint"
- user_mapping_provider:
- config:
- localpart_template: "{{ user.preferred_username }}"
- display_name_template: "{{ user.name }}"
-
-Apple
-Configuring "Sign in with Apple" (SiWA) requires an Apple Developer account.
-You will need to create a new "Services ID" for SiWA, and create and download a -private key with "SiWA" enabled.
-As well as the private key file, you will need:
--
-
- Client ID: the "identifier" you gave the "Services ID" -
- Team ID: a 10-character ID associated with your developer account. -
- Key ID: the 10-character identifier for the key. -
https://help.apple.com/developer-account/?lang=en#/dev77c875b7e has more -documentation on setting up SiWA.
-The synapse config will look like this:
- - idp_id: apple
- idp_name: Apple
- issuer: "https://appleid.apple.com"
- client_id: "your-client-id" # Set to the "identifier" for your "ServicesID"
- client_auth_method: "client_secret_post"
- client_secret_jwt_key:
- key_file: "/path/to/AuthKey_KEYIDCODE.p8" # point to your key file
- jwt_header:
- alg: ES256
- kid: "KEYIDCODE" # Set to the 10-char Key ID
- jwt_payload:
- iss: TEAMIDCODE # Set to the 10-char Team ID
- scopes: ["name", "email", "openid"]
- authorization_endpoint: https://appleid.apple.com/auth/authorize?response_mode=form_post
- user_mapping_provider:
- config:
- email_template: "{{ user.email }}"
-
-Django OAuth Toolkit
-django-oauth-toolkit is a -Django application providing out of the box all the endpoints, data and logic -needed to add OAuth2 capabilities to your Django projects. It supports -OpenID Connect too.
-Configuration on Django's side:
--
-
- Add an application: https://example.com/admin/oauth2_provider/application/add/ and choose parameters like this: -
-
-
Redirect uris
: https://synapse.example.com/_synapse/client/oidc/callback
-Client type
:Confidential
-Authorization grant type
:Authorization code
-Algorithm
:HMAC with SHA-2 256
-
-
-
-
-
You can customize the claims Django gives to synapse (optional):
---Code sample
-
-class CustomOAuth2Validator(OAuth2Validator): - - def get_additional_claims(self, request): - return { - "sub": request.user.email, - "email": request.user.email, - "first_name": request.user.first_name, - "last_name": request.user.last_name, - } -
-
Your synapse config is then:
-oidc_providers:
- - idp_id: django_example
- idp_name: "Django Example"
- issuer: "https://example.com/o/"
- client_id: "your-client-id" # CHANGE ME
- client_secret: "your-client-secret" # CHANGE ME
- scopes: ["openid"]
- user_profile_method: "userinfo_endpoint" # needed because oauth-toolkit does not include user information in the authorization response
- user_mapping_provider:
- config:
- localpart_template: "{{ user.email.split('@')[0] }}"
- display_name_template: "{{ user.first_name }} {{ user.last_name }}"
- email_template: "{{ user.email }}"
-
-
-