Get started - it's free!
Log in
© 2025

Workload identity federation

Workload identity federation is currently in beta.

Workload identity federation allows cloud-hosted infrastructure in providers like Microsoft Azure, Google Cloud Platform, or GitHub Actions to authenticate to a tailnet or the Tailscale API using provider-native identity tokens instead of Tailscale auth keys or OAuth clients. By leveraging the provider's federated OpenID Connect (OIDC) identities, tailnet administrators can simplify credential management and infrastructure automation.

How it works

A process flow diagram for a standard workload identity federation flow, showing how a cloud workload can exchange a signed JWT from its provider with Tailscale to authenticate itself to the Tailscale API.

When a cloud workload (such as a CI job, serverless function, or virtual machine) wants to join your tailnet or call the Tailscale API, it first asks its own platform for an OIDC token.

The OIDC token is a signed JSON Web Token (JWT) that conveys three assurances from the cloud platform:

  • It vouches for the workload's identity.
  • It specifies exactly which workload the JWT represents.
  • It declares who is permitted to consume the token.

Because the platform signs the token with its publicly advertised keys, anyone can verify the signature and trust that the claims are genuine.

Before any exchange can take place, a tailnet admin establishes trust by specifying the OIDC issuer to trust and defining claim-matching rules that map specific workloads, such as a particular GitHub repository, Google Cloud service account, or Azure workload, onto the tags and API scopes they should receive. Tokens that fail to match these rules are rejected automatically.

The workload then sends that OIDC token to Tailscale's token exchange endpoint. Behind the scenes, Tailscale fetches the issuer's public keys, validates the signature, standard claims (issuer, audience, expiry), and claim-matching rules and then returns a short-lived API token with the scopes you configured when configuring identity federation in the Tailscale admin console.

With this API token, the workload can join or manage the tailnet with the Tailscale API.

Get started

You need to configure a federate identity in the admin console and exchange workload identity tokens with Tailscale.

Configure federated identities in the admin console

Before a cloud workload can use its signed OIDC token to authenticate to Tailscale, you must set up a federated identity in Tailscale and assign all necessary scopes.

  1. Open the Trust credentials page of the admin console.
  2. Select the Credential button.
  3. Select OpenID Connect.
  4. Select an Issuer from the dropdown. Common cloud providers are included in the dropdown, but any infrastructure provider that supports OIDC for workload identity federation can be used if Custom issuer is selected.
    1. Enter the Issuer URL for the cloud provider's OIDC issuer if using a Custom issuer.
  5. Enter the Subject. This value determines the attributes of the workload that must match in order to receive a Tailscale API token. Learn more about the syntax of the subject (sub) claims for common cloud providers:
  6. (Optional) Add additional Custom claims to further narrow access.
  7. Select the relevant read and write scopes from the list and select Generate credential.
  8. Copy the Client ID and Audience (aud claim). These are not secrets, and you will be able to view them in the admin console.

Claim value format

Values specified for the subject and custom claims are matched against claims values in the OIDC JWT.

Values can contain an * to match against any character. Other characters specified must directly match the value of the sub claim.

For example, specifying my-example-sub/* for the subject will successfully match sub claims that start with my-example-sub/.

Exchange workload identity tokens with Tailscale

In order to act on the Tailscale API, you must exchange the workload's signed OIDC JWT for a short-lived Tailscale API token.

This example shows how GitHub actions can retrieve an OIDC JWT, exchange it for a short-lived Tailscale API token, and then use that Tailscale API token to call the Tailscale API. When configuring the credential in the Tailscale admin console, you will need to select the devices:read scope.

permissions:
  id-token: write # This is required for requesting the JWT
  contents: read # This is required for actions/checkout

on:
  workflow_dispatch:
    inputs:
      audience:
        description: "Audience for the OIDC token"
        required: true
        default: "<api.tailscale.com/ID>"
      client_id:
        description: "Client ID for the Tailscale OIDC JWT exchange"
        required: true
        default: "<tailnet-id/client-id>"
      tailnet:
        description: "Tailnet name for the demo API request"
        required: true
        default: "<your-tailnet-name>"

jobs:
  echo-token:
    runs-on: ubuntu-latest
    steps:
      - name: get OIDC token from GitHub Actions
        id: get_oidc_token
        run: |
          JWT=$(curl -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=${{ inputs.audience }}" | jq -r '.value')
          echo "::add-mask::$JWT" # Mask the JWT in the logs
          echo "jwt=$JWT" >> $GITHUB_OUTPUT
      - name: perform OIDC token exchange
        run: |
          # Perform the OIDC token exchange with Tailscale
          RESPONSE=$(curl -X POST https://api.tailscale.com/api/v2/oauth/token-exchange \
            -H "Content-Type: application/x-www-form-urlencoded" \
            -d "client_id=${{ inputs.client_id}}" \
            -d "jwt=${{ steps.get_oidc_token.outputs.jwt }}")
          # make API request to demonstrate access token
          export ACCESS_TOKEN=$(echo $RESPONSE | jq -r '.access_token')
          echo "::add-mask::$ACCESS_TOKEN" # Mask the access token in the logs
          curl https://api.tailscale.com/api/v2/tailnet/${{ inputs.tailnet }}/devices \
            --header "Authorization: Bearer ${ACCESS_TOKEN}"

To test this workflow:

  1. Save the YAML above as token.yaml in your repository's .github/workflows directory.
  2. Visit the Actions tab of your repository and select .github/workflows/token.yaml in the sidebar.
  3. Select Run workflow.
  4. In the dropdown, paste the Audience (aud claim) and Client ID that you generated when configuring the federated identity in the Tailscale admin console. Lastly, enter the tailnet name, which is your tailnet ID. You can find your tailnet ID in the General page of the admin console.
  5. Select Run workflow.
  6. After a few seconds, the workflow will appear in the workflow runs table. To confirm that it ran successfully:
    1. Select the workflow from the table.
    2. Select the echo-token action on the workflow detail page.
    3. Expand the perform OIDC token exchange step.
    4. The workflow step's output should display a JSON object listing all of the devices in your tailnet.

Register new nodes using workload identity

A device must run Tailscale v1.90.1 or later to have the --client-id and --id-token flags.

You can use a client ID and OIDC token directly in tailscale up to register a new node:

tailscale up --client-id=${CLIENT_ID} --id-token=${IDENTITY_TOKEN} --advertise-tags=tag:ci

The workload identity credential must have the auth_keys scope and the tags passed to --advertise-tags must match the tags you selected when you configured the federated identity.

The --client-id flag can accept additional URL-style parameters:

tailscale up --client-id='${CLIENT_ID}?ephemeral=false&preauthorized=true'--id-token=${IDENTITY_TOKEN} --advertise-tags=tag:ci

The available parameters are:

Limitations

  • The issuer that provides signed JWTs to your workloads must be publicly accessible.

Last updated Oct 30, 2025