Currently Available: Need a skilled Software Developer for your next project?
Categories
Self-Hosting

How to Use GitHub Login with a Self-Hosted VPN Like Headscale or NetBird

To let people sign in to your self-hosted VPN with GitHub, connect GitHub to an identity broker, then connect the broker to the VPN. The broker accepts a person’s sign-in from one provider and gives another service an identity it trusts.

This extra step is necessary because Headscale and NetBird use OpenID Connect (OIDC), a standard for sending identity information in signed tokens. GitHub supports OAuth, which lets an app get permission to access a person’s GitHub account. But GitHub says its OAuth flows do not issue OIDC identity tokens. The documented path is GitHub → identity broker → Headscale or NetBird. GitHub’s authentication documentation explains why you cannot use GitHub directly as the VPN’s OIDC provider.

The broker handles two separate sign-ins: GitHub sends the user back to the broker, then the broker sends the user back to the VPN. A callback URL is the address a service sends the user to after sign-in. Register each callback URL with the service that sends the user there. After sign-in, configure who may join the VPN and what network resources they can reach.

Connect GitHub through an identity broker

Authentik is one option: it can use GitHub as an upstream OAuth sign-in source and provide OIDC to a separate service. Authentik’s GitHub source instructions describe the GitHub connection, while its OIDC provider documentation covers providing sign-in to another service. Dex also documents a GitHub connector, but NetBird’s self-hosted instructions do not say that its built-in Dex supports a direct GitHub connector. Use a broker setup documented for your deployment.

First, create a GitHub OAuth App and set its callback URL to the broker’s GitHub-source callback. Authentik’s documented pattern is https://authentik.company/source/oauth/callback/github; replace the hostname with the one used by your Authentik installation. GitHub returns the user to this URL after authorization. This URL is for the broker, not the VPN. GitHub’s OAuth App setup instructions explain how to register the app. Enter the exact callback URL and request only the GitHub permissions the broker needs for sign-in. Do not grant repository access unless another feature requires it.

Next, register the VPN as an OIDC client in the broker. The broker then supplies an issuer URL, a client ID, and a client secret. The issuer URL identifies the broker that issues identity tokens for the VPN. Register the VPN’s callback URL with the broker too. These credentials connect the VPN to the broker. Keep the GitHub OAuth secret in the broker, and keep both secrets out of client-side code and public repositories.

Finally, test each part of the sign-in path. Confirm that GitHub returns the user to the broker, that the broker signs the user in and supplies the identity details the VPN expects (called claims), and that the VPN accepts the broker’s OIDC response. A successful sign-in confirms the user’s identity, but does not grant access to every VPN peer or network.

Configure Headscale to use the broker

Headscale reads its OIDC settings from its server configuration. In the broker, register Headscale’s callback using the hostname where users reach Headscale. The documented callback pattern is:

https://headscale.example.com/oidc/callback

Then set Headscale’s issuer and client credentials to the values from the broker. Headscale’s OIDC reference recommends PKCE, a protection that binds the sign-in request to the client that started it, with the S256 challenge method. A simplified configuration looks like this:

oidc:
  issuer: "https://idp.example.com/your-issuer"
  client_id: "headscale"
  client_secret: "replace-with-a-secret"
  pkce:
    enabled: true

Replace the example issuer and secret with the broker’s actual values, and check the configuration syntax against the Headscale version you run. Headscale documents one configured OIDC provider. Changing providers can also change the provider identifiers associated with existing users, so treat a provider migration as a user-record change rather than a simple URL update.

Headscale’s OIDC filters let an operator limit who may join. The operator can filter by domain, by user, by email, or by group. Headscale disables these filters by default, and each user must pass every filter you configure. Check the identity details the broker sends before relying on an email or group rule. Headscale normally synchronizes an email only when the provider marks it as verified. So an email rule depends on the email information available from the GitHub account and on how the broker maps that information to a claim.

GitHub sign-in and Headscale client enrollment are separate steps. The client still needs to connect to the Headscale server, and the operator may need to register or approve it. Headscale’s getting-started instructions show the client connection command, tailscale up --login-server <YOUR_HEADSCALE_URL>, and explain the separate registration flow.

Configure NetBird to use the broker

In the documented self-hosted setup, add the broker as an external OIDC provider in the NetBird dashboard. Go to Settings → Identity Providers, add a provider, choose the generic OIDC option, and enter the broker’s issuer and client details. NetBird shows the redirect URL that you must register with the broker. Use this URL as the callback from the broker to NetBird, and enter the broker’s issuer URL rather than a GitHub URL. NetBird’s self-hosted identity-provider instructions describe these steps.

NetBird’s self-hosted documentation also supports local user accounts alongside external identity providers. Starting with NetBird version 0.62, the documentation says an external provider is no longer required for local username-and-password accounts. A local account can provide an administrative recovery path if an external provider becomes unavailable, provided the deployment’s account and access policies allow that use. Check the documentation for your deployed version because older self-hosted architectures use different configuration approaches.

Keep sign-in separate from VPN access

GitHub login answers who is signing in. Headscale or NetBird policy determines what that identity can do after sign-in. Set VPN access rules separately, and test them with the identities you intend to allow. For Headscale, verify the email and group claims before enabling filters that depend on them. For NetBird, verify that the broker’s identity information matches the user and group controls you configure.

Keep both sets of credentials secure. Store the GitHub OAuth credentials in the broker, and store the VPN’s OIDC client secret in its server-side configuration or supported provider settings. If a callback mismatch stops sign-in, compare the registered URL with the exact callback shown by the broker or VPN. A GitHub-to-broker callback error happens at a different point in sign-in than a broker-to-VPN callback error.

What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Email updates

Usually a new article and a few links I found interesting.

No spam. Unsubscribe with one click.

Leave a Reply

Your email address will not be published. Required fields are marked *