Skip to content

OpenID Connect

Headscale supports authentication via external identity providers using OpenID Connect (OIDC). It features:

Please see limitations for known issues and limitations.

Configuration

OpenID requires configuration in Headscale and your identity provider:

  • Headscale: The oidc section of the Headscale configuration contains all available configuration options along with a description and their default values.
  • Identity provider: Please refer to the official documentation of your identity provider for specific instructions. Additionally, there might be some useful hints in the Identity provider specific configuration section below.

Basic configuration

A basic configuration connects Headscale to an identity provider and typically requires:

  • OpenID Connect Issuer URL from the identity provider. Headscale uses the OpenID Connect Discovery Protocol 1.0 to automatically obtain OpenID configuration parameters (example: https://sso.example.com).
  • Client ID from the identity provider (example: headscale).
  • Client secret generated by the identity provider (example: generated-secret).
  • Redirect URI for your identity provider (example: https://headscale.example.com/oidc/callback).
oidc:
  issuer: "https://sso.example.com"
  client_id: "headscale"
  client_secret: "generated-secret"
  • Create a new confidential client (Client ID, Client secret)
  • Add Headscale's OIDC callback URL as valid redirect URL: https://headscale.example.com/oidc/callback
  • Configure additional parameters to improve user experience such as: name, description, logo, …

Proof Key for Code Exchange (PKCE) adds an additional layer of security to the OAuth 2.0 authorization code flow by preventing authorization code interception attacks, see: https://datatracker.ietf.org/doc/html/rfc7636. PKCE is recommended and needs to be configured for Headscale and the identity provider alike:

oidc:
  issuer: "https://sso.example.com"
  client_id: "headscale"
  client_secret: "generated-secret"
  pkce:
    enabled: true
  • Enable PKCE for the headscale client
  • Set the PKCE challenge method to "S256"

Authorize users with filters

Headscale allows to filter for allowed users based on their domain, email address or group membership. These filters can be helpful to apply additional restrictions and control which users are allowed to join. Filters are disabled by default, users are allowed to join once the authentication with the identity provider succeeds. In case multiple filters are configured, a user needs to pass all of them.

  • Check the email domain of each authenticating user against the list of allowed domains and only authorize users whose email domain matches example.com.
  • Access allowed: alice@example.com
  • Access denied: bob@example.net
oidc:
  issuer: "https://sso.example.com"
  client_id: "headscale"
  client_secret: "generated-secret"
  allowed_domains:
    - "example.com"
  • Check the email address of each authenticating user against the list of allowed email addresses and only authorize users whose email is part of the allowed_users list.
  • Access allowed: alice@example.com, bob@example.net
  • Access denied: mallory@example.net
oidc:
  issuer: "https://sso.example.com"
  client_id: "headscale"
  client_secret: "generated-secret"
  allowed_users:
    - "alice@example.com"
    - "bob@example.net"
  • Use the OIDC groups claim of each authenticating user to get their group membership and only authorize users which are members in at least one of the referenced groups.
  • Access allowed: users in the headscale_users group
  • Access denied: users without groups, users with other groups
oidc:
  issuer: "https://sso.example.com"
  client_id: "headscale"
  client_secret: "generated-secret"
  scope: ["openid", "profile", "email", "groups"]
  allowed_groups:
    - "headscale_users"

Customize node expiration

The node expiration is the amount of time a node is authenticated with OpenID Connect until it expires and needs to reauthenticate. The default node expiration is 180 days. This can either be customized or set to the expiration from the Access Token.

oidc:
  issuer: "https://sso.example.com"
  client_id: "headscale"
  client_secret: "generated-secret"
  expiry: 30d   # Use 0 to disable node expiration

Please keep in mind that the Access Token is typically a short-lived token that expires within a few minutes. You will have to configure token expiration in your identity provider to avoid frequent reauthentication.

oidc:
  issuer: "https://sso.example.com"
  client_id: "headscale"
  client_secret: "generated-secret"
  use_expiry_from_token: true

Expire a node and force re-authentication

A node can be expired immediately via:

headscale node expire -i <NODE_ID>

Reference a user in the policy

You may refer to users in the Headscale policy via:

  • Email address
  • Username
  • Provider identifier (only available in the database or from your identity provider)

A user identifier in the policy must contain a single @

The Headscale policy requires a single @ to reference a user. If the username or provider identifier doesn't already contain a single @, it needs to be appended at the end. For example: the username ssmith has to be written as ssmith@ to be correctly identified as user within the policy.

Email address or username might be updated by users

Many identity providers allow users to update their own profile. Depending on the identity provider and its configuration, the values for username or email address might change over time. This might have unexpected consequences for Headscale where a policy might no longer work or a user might obtain more access by hijacking an existing username or email address.

Supported OIDC claims

Headscale uses the standard OIDC claims to populate and update its local user profile on each login. OIDC claims are read from the ID Token or from the UserInfo endpoint.

Headscale profile OIDC claim Notes / examples
email address email Only used when email_verified: true
display name name eg: Sam Smith
username preferred_username Depends on identity provider, eg: ssmith, ssmith@idp.example.com, \\example.com\ssmith
profile picture picture URL to a profile picture or avatar
provider identifier iss, sub A stable and unique identifier for a user, typically a combination of iss and sub OIDC claims
groups Only used to filter for allowed groups

Limitations

  • Support for OpenID Connect aims to be generic and vendor independent. It offers only limited support for quirks of specific identity providers.
  • OIDC groups cannot be used in ACLs.
  • The username provided by the identity provider needs to adhere to this pattern:
    • The username must be at least two characters long.
    • It must only contain letters, digits, hyphens, dots, underscores, and up to a single @.
    • The username must start with a letter.
  • A user's email address is only synchronized to the local user profile when the identity provider marks the email address as verified (email_verified: true).

Please see the GitHub label "OIDC" for OIDC related issues.

Identity provider specific configuration

Third-party software and services

This section of the documentation is specific for third-party software and services. We recommend users read the third-party documentation on how to configure and integrate an OIDC client. Please see the Configuration section for a description of Headscale's OIDC related configuration settings.

Any identity provider with OpenID Connect support should "just work" with Headscale. The following identity providers are known to work:

Authelia

Authelia is fully supported by Headscale.

Additional configuration to authorize users based on filters

Authelia (4.39.0 or newer) no longer provides standard OIDC claims such as email or groups via the ID Token. The OIDC email and groups claims are used to authorize users with filters. This extra configuration step is only needed if you need to authorize access based on one of the following user properties:

  • domain
  • email address
  • group membership

Please follow the instructions from Authelia's documentation on how to Restore Functionality Prior to Claims Parameter.

Authentik

Google OAuth

No username due to missing preferred_username

Google OAuth does not send the preferred_username claim when the scope profile is requested. The username in Headscale will be blank/not set.

In order to integrate Headscale with Google, you'll need to have a Google Cloud Console account.

Google OAuth has a verification process if you need to have users authenticate who are outside of your domain. If you only need to authenticate users from your domain name (ie @example.com), you don't need to go through the verification process.

However if you don't have a domain, or need to add users outside of your domain, you can manually add emails via Google Console.

Steps

  1. Go to Google Console and login or create an account if you don't have one.
  2. Create a project (if you don't already have one).
  3. On the left hand menu, go to APIs and services -> Credentials
  4. Click Create Credentials -> OAuth client ID
  5. Under Application Type, choose Web Application
  6. For Name, enter whatever you like
  7. Under Authorised redirect URIs, add Headscale's OIDC callback URL: https://headscale.example.com/oidc/callback
  8. Click Save at the bottom of the form
  9. Take note of the Client ID and Client secret, you can also download it for reference if you need it.
  10. Configure Headscale following the "Basic configuration" steps. The issuer URL for Google OAuth is: https://accounts.google.com.

Kanidm

  • Kanidm is fully supported by Headscale.
  • Groups for the allowed groups filter need to be specified with their full SPN, for example: headscale_users@sso.example.com.

Keycloak

Keycloak is fully supported by Headscale.

Additional configuration to use the allowed groups filter

Keycloak has no built-in client scope for the OIDC groups claim. This extra configuration step is only needed if you need to authorize access based on group membership.

  • Create a new client scope groups for OpenID Connect:
    • Configure a Group Membership mapper with name groups and the token claim name groups.
    • Enable the mapper for the ID Token, Access Token and UserInfo endpoint.
  • Configure the new client scope for your Headscale client:
    • Edit the Headscale client.
    • Search for the client scope group.
    • Add it with assigned type Default.
  • Configure the allowed groups in Headscale. Keep in mind that groups in Keycloak start with a leading /.

Microsoft Entra ID

In order to integrate Headscale with Microsoft Entra ID, you'll need to provision an App Registration with the correct scopes and redirect URI.

Configure Headscale following the "Basic configuration" steps. The issuer URL for Microsoft Entra ID is: https://login.microsoftonline.com/<tenant-UUID>/v2.0. The following extra_params might be useful:

  • domain_hint: example.com to use your own domain
  • prompt: select_account to force an account picker during login