{"slug":"oauth-clients","title":"OAuth clients","tags":["tailscale","auth"],"agent_summary":"Last validated: Jan 5, 2026","trigger_phrases":[],"runnable":false,"markdown":"\r\n# OAuth clients\r\n\r\nLast validated: Jan 5, 2026\r\n\r\nOAuth clients allow for ongoing access to the [Tailscale API](https://tailscale.com/docs/reference/tailscale-api) using the [client credentials flow](https://www.rfc-editor.org/rfc/rfc6749.html#section-4.4) of the [OAuth 2.0 protocol](https://www.rfc-editor.org/rfc/rfc6749.html).\r\n\r\n## [How it works](https://tailscale.com/docs/features/oauth-clients\\#how-it-works)\r\n\r\nYou create an OAuth client that defines the [scopes](https://tailscale.com/docs/reference/trust-credentials#scopes) to allow when your client application uses the Tailscale API. An example scope is `dns:read`, which grants read-only access to a tailnet's DNS settings. Another example is the `devices:core` scope, which grants access to read and write the list of devices in the tailnet, authorize or remove machines, and manipulate tags on devices.\r\n\r\nTailscale restricts scopes to only the necessary Tailscale API endpoints needed for an operation. For example, tokens with the `dns:read` scope can access only the following Tailscale API endpoints:\r\n\r\n- `GET /api/v2/tailnet/:tailnet/dns/nameservers`\r\n- `GET /api/v2/tailnet/:tailnet/dns/preferences`\r\n- `GET /api/v2/tailnet/:tailnet/dns/searchpaths`\r\n- `GET /api/v2/tailnet/:tailnet/keys/:keyID` (for itself only)\r\n\r\nAn OAuth client consists of a client ID and a client secret. When you create an OAuth client, Tailscale creates these for you. Within your client application, use the client ID and client secret to request an API access token from the [Tailscale OAuth token endpoint](https://tailscale.com/docs/features/oauth-clients#tailscale-oauth-token-endpoint). You use the access token to make calls to the Tailscale API. The access token grants permission only for the scopes that you defined when you created the OAuth client.\r\n\r\nAn API access token expires after one hour. For continuous access, shortly before an API access token expires, request a new API access token from the Tailscale OAuth token endpoint.\r\n\r\nOAuth client libraries in popular programming languages can handle the API access token generation and renewal.\r\n\r\nThe Tailscale OAuth implementation uses the [OAuth 2.0 protocol](https://www.rfc-editor.org/rfc/rfc6749.html).\r\n\r\n## [Prerequisites](https://tailscale.com/docs/features/oauth-clients\\#prerequisites)\r\n\r\nYou need to be an [Owner, Admin, Network admin, or IT admin](https://tailscale.com/docs/reference/user-roles) of a tailnet to create, revoke, or delete OAuth clients.\r\n\r\nOwners and Admins can create an OAuth client with any scope and any [tag](https://tailscale.com/docs/features/tags) that is in the tailnet. Other users can create an OAuth client with only the scopes and tags for which they have permissions. For example, a Network admin cannot grant the `devices:core` scope, but an IT admin can.\r\n\r\n## [Setting up an OAuth client](https://tailscale.com/docs/features/oauth-clients\\#setting-up-an-oauth-client)\r\n\r\n1. Open the [Trust credentials](https://login.tailscale.com/admin/settings/trust-credentials) page of the admin console.\r\n\r\n2. Select the **Credential** button.\r\n\r\n3. Select **OAuth**.\r\n\r\n4. Select the set of operations that can be performed with tokens created by the new OAuth client. For a given operation, select **Read** or **Write**. For a description of the operations, refer to [Scopes](https://tailscale.com/docs/reference/trust-credentials#scopes).\r\n\r\n5. Select **Generate credential**.\r\n\r\n6. In the **Credential created** page, you can access the new OAuth client's ID and secret. Copy both the client ID and secret, as you need them for your client code. Note that after you close the **Credential created** page, you won't be able to copy the secret again.\r\n\r\n\r\n\r\nStore the client secret securely.\r\n\r\n\r\n![The 'Generate OAuth client' page in the admin console](https://tailscale.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgenerated-oauth-client.6e110b27.jpg&w=750&q=75)\r\n7. Select **Done**.\r\n\r\nYour OAuth client is now configured. Use the client ID and secret when you configure your OAuth client application. Note that Tailscale-generated OAuth client secrets are case-sensitive.\r\n\r\n\r\nIf a user creates an OAuth client, the OAuth client will continue to function and generate API access tokens even if the user no longer has access to the tailnet. Admins can access all configured OAuth clients in the [Trust credentials](https://login.tailscale.com/admin/settings/trust-credentials) page of the admin console.\r\n\r\n## [Tailscale OAuth token endpoint](https://tailscale.com/docs/features/oauth-clients\\#tailscale-oauth-token-endpoint)\r\n\r\nThe Tailscale OAuth token endpoint is `https://api.tailscale.com/api/v2/oauth/token`.\r\n\r\nMake requests to the Tailscale OAuth token endpoint when you need an API access token. The Tailscale OAuth token endpoint accepts requests that conform to the OAuth 2.0 client credentials grant [request format](https://www.rfc-editor.org/rfc/rfc6749.html#section-4.4.2), and returns responses that conform to the OAuth 2.0 client credentials grant [response format](https://www.rfc-editor.org/rfc/rfc6749.html#section-4.4.3).\r\n\r\nRequests to the OAuth token endpoint can include `scope` and `tags` request parameters, which specify space-delimited lists of requested scopes and [tags](https://tailscale.com/docs/features/tags), respectively. The OAuth client must have permission to grant the requested scopes and tags. For example, an OAuth client with the `all` scope (which grants all other scopes as well as all device tags) can request an access token with the `devices:core` scope and the `tag:server` tag.\r\n\r\nTags are only relevant for tokens with the `devices:core`, `auth_keys`, or `all` scopes. The OAuth client ignores tags if none of these scopes are present. The `tags` parameter is not part of the OAuth 2.0 specification, and not all clients might support it.\r\n\r\n## [OAuth client libraries](https://tailscale.com/docs/features/oauth-clients\\#oauth-client-libraries)\r\n\r\nPopular programming languages provide OAuth client libraries for using OAuth clients. Here are several:\r\n\r\n- Go: `clientcredentials` [Visit page →](https://pkg.go.dev/golang.org/x/oauth2/clientcredentials)\r\n- Node: `OAuth2` [Visit page →](https://github.com/ciaranj/node-oauth#oauth20)\r\n- PHP: `ClientCredentials.php` [Visit page →](https://github.com/thephpleague/oauth2-client/blob/master/src/Grant/ClientCredentials.php)\r\n- Ruby: `client_credentials.rb` [Visit page →](https://gitlab.com/oauth-xx/oauth2/blob/main/lib/oauth2/strategy/client_credentials.rb)\r\n- Rust: `Client Credentials Grant` [Visit page →](https://docs.rs/oauth2/latest/oauth2/#client-credentials-grant)\r\n\r\nFor example, the following Go code shows how to create an OAuth client object that uses your client ID and client secret to generate an API access token for calls to the Tailscale API:\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n        \"context\"\r\n        \"fmt\"\r\n        \"io/ioutil\"\r\n        \"log\"\r\n        \"os\"\r\n\r\n        \"golang.org/x/oauth2/clientcredentials\"\r\n)\r\n\r\nfunc main() {\r\n        var oauthConfig = &clientcredentials.Config{\r\n                ClientID:     os.Getenv(\"OAUTH_CLIENT_ID\"),\r\n                ClientSecret: os.Getenv(\"OAUTH_CLIENT_SECRET\"),\r\n                TokenURL:     \"https://api.tailscale.com/api/v2/oauth/token\",\r\n        }\r\n\r\n        client := oauthConfig.Client(context.Background())\r\n        // Replace example.com with your tailnet ID.\r\n        resp, err := client.Get(\"https://api.tailscale.com/api/v2/tailnet/example.com/devices\")\r\n        if err != nil {\r\n                log.Fatalf(\"error getting keys: %v\", err)\r\n        }\r\n\r\n        body, err := ioutil.ReadAll(resp.Body)\r\n        if err != nil {\r\n                log.Fatalf(\"error reading response body: %v\", err)\r\n        }\r\n\r\n        fmt.Printf(\"response: %s\", string(body))\r\n}\r\n```\r\n\r\nThe example requires that you define environment variables `OAUTH_CLIENT_ID` and `OAUTH_CLIENT_SECRET`, with their values set to the **Client ID** and **Client secret** that you create when you [set up an OAuth client](https://tailscale.com/docs/features/oauth-clients#setting-up-an-oauth-client).\r\n\r\n## [Verifying you can generate API access tokens](https://tailscale.com/docs/features/oauth-clients\\#verifying-you-can-generate-api-access-tokens)\r\n\r\nAfter you [set up an OAuth client](https://tailscale.com/docs/features/oauth-clients#setting-up-an-oauth-client), you can confirm that you can generate API access tokens by making a `curl` request to the [Tailscale OAuth token endpoint](https://tailscale.com/docs/features/oauth-clients#tailscale-oauth-token-endpoint).\r\n\r\n```shell\r\n curl -d \"client_id=${OAUTH_CLIENT_ID}\" -d \"client_secret=${OAUTH_CLIENT_SECRET}\" \\\r\n     \"https://api.tailscale.com/api/v2/oauth/token\"\r\n```\r\n\r\nThe example requires that you define environment variables `OAUTH_CLIENT_ID` and `OAUTH_CLIENT_SECRET`, with their values set to your **Client ID** and **Client secret**.\r\n\r\nHere's an example response showing the API access token:\r\n\r\n```json\r\n{\"access_token\":\"tskey-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\",\"token_type\":\"Bearer\",\"expires_in\":3600,\"scope\":\"devices\"}\r\n```\r\n\r\n## [Generating long-lived auth keys](https://tailscale.com/docs/features/oauth-clients\\#generating-long-lived-auth-keys)\r\n\r\nYou cannot generate long-lived [auth keys](https://tailscale.com/docs/features/access-control/auth-keys), because they expire after 90 days, or, for one-off keys, as soon as you use them.\r\n\r\nInstead of a long-lived auth key, you can generate an OAuth client with the `auth_keys` scope. Use the OAuth client to generate new auth keys as needed, by making a `POST` request to the [`/api/v2/tailnet/:tailnet/keys`](https://tailscale.com/api#tag/devices/POST/device/%7BdeviceId%7D/key) API method. When you create an OAuth client with the scope `auth_keys`, you must select one or more [tags](https://tailscale.com/docs/features/tags), which can be any tag or set of tags in your tailnet. You must also specify these tags in the API call.\r\n\r\nFor example, to assign your device a specific tag, such as `tag:server`, create an OAuth client with `tag:server`. When you create the auth key, specify `tag:server` as the tag for the auth key.\r\n\r\nAlternatively, if you need an OAuth client that supports more than one tag, set up [tag ownership](https://tailscale.com/docs/features/tags#ownership). For example, to tag some devices with `tag:server` and others with `tag:database`:\r\n\r\n1. Set up a tag owner `tag:terraform-tag-owner` for both `tag:server` and `tag:database`:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```json\r\n{\r\n     \"tagOwners\": {\r\n       \"tag:terraform-tag-owner\": [\"<your-email-address>\"],\r\n       \"tag:server\": [\"tag:terraform-tag-owner\"],\r\n       \"tag:database\": [\"tag:terraform-tag-owner\"],\r\n     },\r\n}\r\n```\r\n\r\n2. Create an OAuth client with tag `tag:terraform-tag-owner`.\r\n\r\n3. Create an auth key from that OAuth client, and specify either `tag:server` or `tag:database` as the tag for the auth key.\r\n\r\n\r\n## [Shorthand notation for tailnet ID](https://tailscale.com/docs/features/oauth-clients\\#shorthand-notation-for-tailnet-id)\r\n\r\nWhen you use an access token to make an API call, you can optionally use the value `-` as the [tailnet ID](https://tailscale.com/docs/concepts/tailnet-name#tailnet-id). You can find your tailnet ID in the [General](https://login.tailscale.com/admin/settings/general) page of the admin console. You do not need to specify the tailnet ID.\r\n\r\nFor example, this command:\r\n\r\n```shell\r\ncurl -u $ACCESS_TOKEN: \"https://api.tailscale.com/api/v2/tailnet/example.com/devices\"\r\n```\r\n\r\nis equivalent to:\r\n\r\n```shell\r\ncurl -u $ACCESS_TOKEN: \"https://api.tailscale.com/api/v2/tailnet/-/devices\"\r\n```\r\n\r\nas long as the access token is owned by the `example.com` tailnet.\r\n\r\nYou can also include the access token in the request header by using the `-H` option:\r\n\r\n```shell\r\ncurl -H \"Authorization: Bearer $ACCESS_TOKEN\" \"https://api.tailscale.com/api/v2/tailnet/-/devices\"\r\n```\r\n\r\n## [Register new nodes using OAuth credentials](https://tailscale.com/docs/features/oauth-clients\\#register-new-nodes-using-oauth-credentials)\r\n\r\nYou can use an OAuth secret directly in [`tailscale up`](https://tailscale.com/docs/reference/tailscale-cli/up) to register a new node:\r\n\r\n```shell\r\ntailscale up --auth-key=${OAUTH_CLIENT_SECRET} --advertise-tags=tag:ci\r\n```\r\n\r\nThe OAuth client must have the `auth_keys` scope. When you [create a client](https://tailscale.com/docs/features/oauth-clients#setting-up-an-oauth-client) with the `auth_keys` scope, you assign one or more [tags](https://tailscale.com/docs/features/tags) for the scope. You must pass in one or more of those tags to the `--advertise-tags` flag.\r\n\r\nThe `--auth-key` flag can accept additional URL-style parameters when used with OAuth secrets:\r\n\r\n```shell\r\ntailscale up --auth-key='${OAUTH_CLIENT_SECRET}?ephemeral=false&preauthorized=true' --advertise-tags=tag:ci\r\n```\r\n\r\nThe available parameters are:\r\n\r\n- `ephemeral`: register as an [ephemeral node](https://tailscale.com/docs/features/ephemeral-nodes) (defaults to `true`)\r\n- `preauthorized`: skip manual [device approval](https://tailscale.com/docs/features/access-control/device-management/device-approval) (defaults to `false`)\r\n- `baseURL`: base URL for the Tailscale API (defaults to `https://api.tailscale.com`)\r\n\r\n## [get-authkey utility](https://tailscale.com/docs/features/oauth-clients\\#get-authkey-utility)\r\n\r\nThe `get-authkey` utility returns a new auth key to `stdout`, based on environment variables that contain values for your OAuth client ID and secret. Use `get-authkey` to generate auth keys for scripts or other automation.\r\n\r\nAll auth keys created from an OAuth client must use [tags](https://tailscale.com/docs/features/tags). You can optionally pass in arguments to `get-authkey` to specify whether the [key type](https://tailscale.com/docs/features/access-control/auth-keys#types-of-auth-keys) is ephemeral, reusable, and/or pre-authorized.\r\n\r\n`get-authkey` requires Go 1.23 or later.\r\n\r\nTo build and run `get-authkey` directly:\r\n\r\n1. Set the following environment variables:\r\n\r\n\r\n   - `TS_API_CLIENT_ID`: The OAuth client ID for your tailnet.\r\n   - `TS_API_CLIENT_SECRET`: The OAuth client secret for your tailnet.\r\n\r\n```shell\r\nexport TS_API_CLIENT_ID=<clientID> TS_API_CLIENT_SECRET=<secret>\r\n```\r\n\r\n2. Run:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```shell\r\ngo run tailscale.com/cmd/get-authkey@latest -tags tag:development\r\n```\r\n\r\n\r\nYou can pass in the following parameters:\r\n\r\n- `-tags`: Required. Apply the comma-separated list of tags to the auth key.\r\n- `-reusable` (Optional): Allocate a reusable auth key. If not set, defaults to false.\r\n- `-ephemeral` (Optional): Allocate an ephemeral auth key. If not set, defaults to false.\r\n- `-preauth` (Optional): Allocate the auth key as pre-authorized. If not set, defaults to true.\r\n\r\nFor example:\r\n\r\n```shell\r\ngo run tailscale.com/cmd/get-authkey@latest -reusable -tags tag:development\r\n```\r\n\r\nAs an alternative, you can download the `get-authkey` source code and run it from a local repository:\r\n\r\n1. Clone the [`tailscale/tailscale`](https://github.com/tailscale/tailscale) repository.\r\n\r\n2. Open a command prompt and change directories to the root of the local `tailscale/` folder.\r\n\r\n3. Run `get-authkey`:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```shell\r\ngo run ./cmd/get-authkey/main.go -tags tag:development\r\n```\r\n\r\n\r\n## [Scopes](https://tailscale.com/docs/features/oauth-clients\\#scopes)\r\n\r\nInformation about our scopes has moved to the [trust credentials](https://tailscale.com/docs/reference/trust-credentials#scopes) topic.\r\n\r\n## [Legacy scopes](https://tailscale.com/docs/features/oauth-clients\\#legacy-scopes)\r\n\r\nInformation about our legacy scopes has moved to the [trust credentials](https://tailscale.com/docs/reference/trust-credentials#legacy-scopes) topic.\r\n\r\n## [Limitations](https://tailscale.com/docs/features/oauth-clients\\#limitations)\r\n\r\n- OAuth clients must be owned by the tailnet, and not by an individual user.\r\n- An OAuth access token expires after 1 hour—this time cannot be modified.\r\n\r\n![Project Logo](https://cdn.brandfetch.io/tailscale.com/fallback/lettermark/theme/dark/h/256/w/256/icon?c=1bfwsmEH20zzEfSNTed)\r\n\r\nAsk AI\r\n\r\nreCAPTCHA\r\n\r\nRecaptcha requires verification.\r\n\r\nprotected by **reCAPTCHA**\r\n","html":"<h1>OAuth clients</h1>\n<p>Last validated: Jan 5, 2026</p>\n<p>OAuth clients allow for ongoing access to the <a href=\"https://tailscale.com/docs/reference/tailscale-api\">Tailscale API</a> using the <a href=\"https://www.rfc-editor.org/rfc/rfc6749.html#section-4.4\">client credentials flow</a> of the <a href=\"https://www.rfc-editor.org/rfc/rfc6749.html\">OAuth 2.0 protocol</a>.</p>\n<h2><a href=\"https://tailscale.com/docs/features/oauth-clients#how-it-works\">How it works</a></h2>\n<p>You create an OAuth client that defines the <a href=\"https://tailscale.com/docs/reference/trust-credentials#scopes\">scopes</a> to allow when your client application uses the Tailscale API. An example scope is <code>dns:read</code>, which grants read-only access to a tailnet's DNS settings. Another example is the <code>devices:core</code> scope, which grants access to read and write the list of devices in the tailnet, authorize or remove machines, and manipulate tags on devices.</p>\n<p>Tailscale restricts scopes to only the necessary Tailscale API endpoints needed for an operation. For example, tokens with the <code>dns:read</code> scope can access only the following Tailscale API endpoints:</p>\n<ul>\n<li><code>GET /api/v2/tailnet/:tailnet/dns/nameservers</code></li>\n<li><code>GET /api/v2/tailnet/:tailnet/dns/preferences</code></li>\n<li><code>GET /api/v2/tailnet/:tailnet/dns/searchpaths</code></li>\n<li><code>GET /api/v2/tailnet/:tailnet/keys/:keyID</code> (for itself only)</li>\n</ul>\n<p>An OAuth client consists of a client ID and a client secret. When you create an OAuth client, Tailscale creates these for you. Within your client application, use the client ID and client secret to request an API access token from the <a href=\"https://tailscale.com/docs/features/oauth-clients#tailscale-oauth-token-endpoint\">Tailscale OAuth token endpoint</a>. You use the access token to make calls to the Tailscale API. The access token grants permission only for the scopes that you defined when you created the OAuth client.</p>\n<p>An API access token expires after one hour. For continuous access, shortly before an API access token expires, request a new API access token from the Tailscale OAuth token endpoint.</p>\n<p>OAuth client libraries in popular programming languages can handle the API access token generation and renewal.</p>\n<p>The Tailscale OAuth implementation uses the <a href=\"https://www.rfc-editor.org/rfc/rfc6749.html\">OAuth 2.0 protocol</a>.</p>\n<h2><a href=\"https://tailscale.com/docs/features/oauth-clients#prerequisites\">Prerequisites</a></h2>\n<p>You need to be an <a href=\"https://tailscale.com/docs/reference/user-roles\">Owner, Admin, Network admin, or IT admin</a> of a tailnet to create, revoke, or delete OAuth clients.</p>\n<p>Owners and Admins can create an OAuth client with any scope and any <a href=\"https://tailscale.com/docs/features/tags\">tag</a> that is in the tailnet. Other users can create an OAuth client with only the scopes and tags for which they have permissions. For example, a Network admin cannot grant the <code>devices:core</code> scope, but an IT admin can.</p>\n<h2><a href=\"https://tailscale.com/docs/features/oauth-clients#setting-up-an-oauth-client\">Setting up an OAuth client</a></h2>\n<ol>\n<li>\n<p>Open the <a href=\"https://login.tailscale.com/admin/settings/trust-credentials\">Trust credentials</a> page of the admin console.</p>\n</li>\n<li>\n<p>Select the <strong>Credential</strong> button.</p>\n</li>\n<li>\n<p>Select <strong>OAuth</strong>.</p>\n</li>\n<li>\n<p>Select the set of operations that can be performed with tokens created by the new OAuth client. For a given operation, select <strong>Read</strong> or <strong>Write</strong>. For a description of the operations, refer to <a href=\"https://tailscale.com/docs/reference/trust-credentials#scopes\">Scopes</a>.</p>\n</li>\n<li>\n<p>Select <strong>Generate credential</strong>.</p>\n</li>\n<li>\n<p>In the <strong>Credential created</strong> page, you can access the new OAuth client's ID and secret. Copy both the client ID and secret, as you need them for your client code. Note that after you close the <strong>Credential created</strong> page, you won't be able to copy the secret again.</p>\n</li>\n</ol>\n<p>Store the client secret securely.</p>\n<p><img src=\"https://tailscale.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgenerated-oauth-client.6e110b27.jpg&#x26;w=750&#x26;q=75\" alt=\"The &#x27;Generate OAuth client&#x27; page in the admin console\">\r\n7. Select <strong>Done</strong>.</p>\n<p>Your OAuth client is now configured. Use the client ID and secret when you configure your OAuth client application. Note that Tailscale-generated OAuth client secrets are case-sensitive.</p>\n<p>If a user creates an OAuth client, the OAuth client will continue to function and generate API access tokens even if the user no longer has access to the tailnet. Admins can access all configured OAuth clients in the <a href=\"https://login.tailscale.com/admin/settings/trust-credentials\">Trust credentials</a> page of the admin console.</p>\n<h2><a href=\"https://tailscale.com/docs/features/oauth-clients#tailscale-oauth-token-endpoint\">Tailscale OAuth token endpoint</a></h2>\n<p>The Tailscale OAuth token endpoint is <code>https://api.tailscale.com/api/v2/oauth/token</code>.</p>\n<p>Make requests to the Tailscale OAuth token endpoint when you need an API access token. The Tailscale OAuth token endpoint accepts requests that conform to the OAuth 2.0 client credentials grant <a href=\"https://www.rfc-editor.org/rfc/rfc6749.html#section-4.4.2\">request format</a>, and returns responses that conform to the OAuth 2.0 client credentials grant <a href=\"https://www.rfc-editor.org/rfc/rfc6749.html#section-4.4.3\">response format</a>.</p>\n<p>Requests to the OAuth token endpoint can include <code>scope</code> and <code>tags</code> request parameters, which specify space-delimited lists of requested scopes and <a href=\"https://tailscale.com/docs/features/tags\">tags</a>, respectively. The OAuth client must have permission to grant the requested scopes and tags. For example, an OAuth client with the <code>all</code> scope (which grants all other scopes as well as all device tags) can request an access token with the <code>devices:core</code> scope and the <code>tag:server</code> tag.</p>\n<p>Tags are only relevant for tokens with the <code>devices:core</code>, <code>auth_keys</code>, or <code>all</code> scopes. The OAuth client ignores tags if none of these scopes are present. The <code>tags</code> parameter is not part of the OAuth 2.0 specification, and not all clients might support it.</p>\n<h2><a href=\"https://tailscale.com/docs/features/oauth-clients#oauth-client-libraries\">OAuth client libraries</a></h2>\n<p>Popular programming languages provide OAuth client libraries for using OAuth clients. Here are several:</p>\n<ul>\n<li>Go: <code>clientcredentials</code> <a href=\"https://pkg.go.dev/golang.org/x/oauth2/clientcredentials\">Visit page →</a></li>\n<li>Node: <code>OAuth2</code> <a href=\"https://github.com/ciaranj/node-oauth#oauth20\">Visit page →</a></li>\n<li>PHP: <code>ClientCredentials.php</code> <a href=\"https://github.com/thephpleague/oauth2-client/blob/master/src/Grant/ClientCredentials.php\">Visit page →</a></li>\n<li>Ruby: <code>client_credentials.rb</code> <a href=\"https://gitlab.com/oauth-xx/oauth2/blob/main/lib/oauth2/strategy/client_credentials.rb\">Visit page →</a></li>\n<li>Rust: <code>Client Credentials Grant</code> <a href=\"https://docs.rs/oauth2/latest/oauth2/#client-credentials-grant\">Visit page →</a></li>\n</ul>\n<p>For example, the following Go code shows how to create an OAuth client object that uses your client ID and client secret to generate an API access token for calls to the Tailscale API:</p>\n<pre><code class=\"language-go\">package main\r\n\r\nimport (\r\n        \"context\"\r\n        \"fmt\"\r\n        \"io/ioutil\"\r\n        \"log\"\r\n        \"os\"\r\n\r\n        \"golang.org/x/oauth2/clientcredentials\"\r\n)\r\n\r\nfunc main() {\r\n        var oauthConfig = &#x26;clientcredentials.Config{\r\n                ClientID:     os.Getenv(\"OAUTH_CLIENT_ID\"),\r\n                ClientSecret: os.Getenv(\"OAUTH_CLIENT_SECRET\"),\r\n                TokenURL:     \"https://api.tailscale.com/api/v2/oauth/token\",\r\n        }\r\n\r\n        client := oauthConfig.Client(context.Background())\r\n        // Replace example.com with your tailnet ID.\r\n        resp, err := client.Get(\"https://api.tailscale.com/api/v2/tailnet/example.com/devices\")\r\n        if err != nil {\r\n                log.Fatalf(\"error getting keys: %v\", err)\r\n        }\r\n\r\n        body, err := ioutil.ReadAll(resp.Body)\r\n        if err != nil {\r\n                log.Fatalf(\"error reading response body: %v\", err)\r\n        }\r\n\r\n        fmt.Printf(\"response: %s\", string(body))\r\n}\n</code></pre>\n<p>The example requires that you define environment variables <code>OAUTH_CLIENT_ID</code> and <code>OAUTH_CLIENT_SECRET</code>, with their values set to the <strong>Client ID</strong> and <strong>Client secret</strong> that you create when you <a href=\"https://tailscale.com/docs/features/oauth-clients#setting-up-an-oauth-client\">set up an OAuth client</a>.</p>\n<h2><a href=\"https://tailscale.com/docs/features/oauth-clients#verifying-you-can-generate-api-access-tokens\">Verifying you can generate API access tokens</a></h2>\n<p>After you <a href=\"https://tailscale.com/docs/features/oauth-clients#setting-up-an-oauth-client\">set up an OAuth client</a>, you can confirm that you can generate API access tokens by making a <code>curl</code> request to the <a href=\"https://tailscale.com/docs/features/oauth-clients#tailscale-oauth-token-endpoint\">Tailscale OAuth token endpoint</a>.</p>\n<pre><code class=\"language-shell\"> curl -d \"client_id=${OAUTH_CLIENT_ID}\" -d \"client_secret=${OAUTH_CLIENT_SECRET}\" \\\r\n     \"https://api.tailscale.com/api/v2/oauth/token\"\n</code></pre>\n<p>The example requires that you define environment variables <code>OAUTH_CLIENT_ID</code> and <code>OAUTH_CLIENT_SECRET</code>, with their values set to your <strong>Client ID</strong> and <strong>Client secret</strong>.</p>\n<p>Here's an example response showing the API access token:</p>\n<pre><code class=\"language-json\">{\"access_token\":\"tskey-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\",\"token_type\":\"Bearer\",\"expires_in\":3600,\"scope\":\"devices\"}\n</code></pre>\n<h2><a href=\"https://tailscale.com/docs/features/oauth-clients#generating-long-lived-auth-keys\">Generating long-lived auth keys</a></h2>\n<p>You cannot generate long-lived <a href=\"https://tailscale.com/docs/features/access-control/auth-keys\">auth keys</a>, because they expire after 90 days, or, for one-off keys, as soon as you use them.</p>\n<p>Instead of a long-lived auth key, you can generate an OAuth client with the <code>auth_keys</code> scope. Use the OAuth client to generate new auth keys as needed, by making a <code>POST</code> request to the <a href=\"https://tailscale.com/api#tag/devices/POST/device/%7BdeviceId%7D/key\"><code>/api/v2/tailnet/:tailnet/keys</code></a> API method. When you create an OAuth client with the scope <code>auth_keys</code>, you must select one or more <a href=\"https://tailscale.com/docs/features/tags\">tags</a>, which can be any tag or set of tags in your tailnet. You must also specify these tags in the API call.</p>\n<p>For example, to assign your device a specific tag, such as <code>tag:server</code>, create an OAuth client with <code>tag:server</code>. When you create the auth key, specify <code>tag:server</code> as the tag for the auth key.</p>\n<p>Alternatively, if you need an OAuth client that supports more than one tag, set up <a href=\"https://tailscale.com/docs/features/tags#ownership\">tag ownership</a>. For example, to tag some devices with <code>tag:server</code> and others with <code>tag:database</code>:</p>\n<ol>\n<li>Set up a tag owner <code>tag:terraform-tag-owner</code> for both <code>tag:server</code> and <code>tag:database</code>:</li>\n</ol>\n<pre><code class=\"language-json\">{\r\n     \"tagOwners\": {\r\n       \"tag:terraform-tag-owner\": [\"&#x3C;your-email-address>\"],\r\n       \"tag:server\": [\"tag:terraform-tag-owner\"],\r\n       \"tag:database\": [\"tag:terraform-tag-owner\"],\r\n     },\r\n}\n</code></pre>\n<ol start=\"2\">\n<li>\n<p>Create an OAuth client with tag <code>tag:terraform-tag-owner</code>.</p>\n</li>\n<li>\n<p>Create an auth key from that OAuth client, and specify either <code>tag:server</code> or <code>tag:database</code> as the tag for the auth key.</p>\n</li>\n</ol>\n<h2><a href=\"https://tailscale.com/docs/features/oauth-clients#shorthand-notation-for-tailnet-id\">Shorthand notation for tailnet ID</a></h2>\n<p>When you use an access token to make an API call, you can optionally use the value <code>-</code> as the <a href=\"https://tailscale.com/docs/concepts/tailnet-name#tailnet-id\">tailnet ID</a>. You can find your tailnet ID in the <a href=\"https://login.tailscale.com/admin/settings/general\">General</a> page of the admin console. You do not need to specify the tailnet ID.</p>\n<p>For example, this command:</p>\n<pre><code class=\"language-shell\">curl -u $ACCESS_TOKEN: \"https://api.tailscale.com/api/v2/tailnet/example.com/devices\"\n</code></pre>\n<p>is equivalent to:</p>\n<pre><code class=\"language-shell\">curl -u $ACCESS_TOKEN: \"https://api.tailscale.com/api/v2/tailnet/-/devices\"\n</code></pre>\n<p>as long as the access token is owned by the <code>example.com</code> tailnet.</p>\n<p>You can also include the access token in the request header by using the <code>-H</code> option:</p>\n<pre><code class=\"language-shell\">curl -H \"Authorization: Bearer $ACCESS_TOKEN\" \"https://api.tailscale.com/api/v2/tailnet/-/devices\"\n</code></pre>\n<h2><a href=\"https://tailscale.com/docs/features/oauth-clients#register-new-nodes-using-oauth-credentials\">Register new nodes using OAuth credentials</a></h2>\n<p>You can use an OAuth secret directly in <a href=\"https://tailscale.com/docs/reference/tailscale-cli/up\"><code>tailscale up</code></a> to register a new node:</p>\n<pre><code class=\"language-shell\">tailscale up --auth-key=${OAUTH_CLIENT_SECRET} --advertise-tags=tag:ci\n</code></pre>\n<p>The OAuth client must have the <code>auth_keys</code> scope. When you <a href=\"https://tailscale.com/docs/features/oauth-clients#setting-up-an-oauth-client\">create a client</a> with the <code>auth_keys</code> scope, you assign one or more <a href=\"https://tailscale.com/docs/features/tags\">tags</a> for the scope. You must pass in one or more of those tags to the <code>--advertise-tags</code> flag.</p>\n<p>The <code>--auth-key</code> flag can accept additional URL-style parameters when used with OAuth secrets:</p>\n<pre><code class=\"language-shell\">tailscale up --auth-key='${OAUTH_CLIENT_SECRET}?ephemeral=false&#x26;preauthorized=true' --advertise-tags=tag:ci\n</code></pre>\n<p>The available parameters are:</p>\n<ul>\n<li><code>ephemeral</code>: register as an <a href=\"https://tailscale.com/docs/features/ephemeral-nodes\">ephemeral node</a> (defaults to <code>true</code>)</li>\n<li><code>preauthorized</code>: skip manual <a href=\"https://tailscale.com/docs/features/access-control/device-management/device-approval\">device approval</a> (defaults to <code>false</code>)</li>\n<li><code>baseURL</code>: base URL for the Tailscale API (defaults to <code>https://api.tailscale.com</code>)</li>\n</ul>\n<h2><a href=\"https://tailscale.com/docs/features/oauth-clients#get-authkey-utility\">get-authkey utility</a></h2>\n<p>The <code>get-authkey</code> utility returns a new auth key to <code>stdout</code>, based on environment variables that contain values for your OAuth client ID and secret. Use <code>get-authkey</code> to generate auth keys for scripts or other automation.</p>\n<p>All auth keys created from an OAuth client must use <a href=\"https://tailscale.com/docs/features/tags\">tags</a>. You can optionally pass in arguments to <code>get-authkey</code> to specify whether the <a href=\"https://tailscale.com/docs/features/access-control/auth-keys#types-of-auth-keys\">key type</a> is ephemeral, reusable, and/or pre-authorized.</p>\n<p><code>get-authkey</code> requires Go 1.23 or later.</p>\n<p>To build and run <code>get-authkey</code> directly:</p>\n<ol>\n<li>\n<p>Set the following environment variables:</p>\n<ul>\n<li><code>TS_API_CLIENT_ID</code>: The OAuth client ID for your tailnet.</li>\n<li><code>TS_API_CLIENT_SECRET</code>: The OAuth client secret for your tailnet.</li>\n</ul>\n</li>\n</ol>\n<pre><code class=\"language-shell\">export TS_API_CLIENT_ID=&#x3C;clientID> TS_API_CLIENT_SECRET=&#x3C;secret>\n</code></pre>\n<ol start=\"2\">\n<li>Run:</li>\n</ol>\n<pre><code class=\"language-shell\">go run tailscale.com/cmd/get-authkey@latest -tags tag:development\n</code></pre>\n<p>You can pass in the following parameters:</p>\n<ul>\n<li><code>-tags</code>: Required. Apply the comma-separated list of tags to the auth key.</li>\n<li><code>-reusable</code> (Optional): Allocate a reusable auth key. If not set, defaults to false.</li>\n<li><code>-ephemeral</code> (Optional): Allocate an ephemeral auth key. If not set, defaults to false.</li>\n<li><code>-preauth</code> (Optional): Allocate the auth key as pre-authorized. If not set, defaults to true.</li>\n</ul>\n<p>For example:</p>\n<pre><code class=\"language-shell\">go run tailscale.com/cmd/get-authkey@latest -reusable -tags tag:development\n</code></pre>\n<p>As an alternative, you can download the <code>get-authkey</code> source code and run it from a local repository:</p>\n<ol>\n<li>\n<p>Clone the <a href=\"https://github.com/tailscale/tailscale\"><code>tailscale/tailscale</code></a> repository.</p>\n</li>\n<li>\n<p>Open a command prompt and change directories to the root of the local <code>tailscale/</code> folder.</p>\n</li>\n<li>\n<p>Run <code>get-authkey</code>:</p>\n</li>\n</ol>\n<pre><code class=\"language-shell\">go run ./cmd/get-authkey/main.go -tags tag:development\n</code></pre>\n<h2><a href=\"https://tailscale.com/docs/features/oauth-clients#scopes\">Scopes</a></h2>\n<p>Information about our scopes has moved to the <a href=\"https://tailscale.com/docs/reference/trust-credentials#scopes\">trust credentials</a> topic.</p>\n<h2><a href=\"https://tailscale.com/docs/features/oauth-clients#legacy-scopes\">Legacy scopes</a></h2>\n<p>Information about our legacy scopes has moved to the <a href=\"https://tailscale.com/docs/reference/trust-credentials#legacy-scopes\">trust credentials</a> topic.</p>\n<h2><a href=\"https://tailscale.com/docs/features/oauth-clients#limitations\">Limitations</a></h2>\n<ul>\n<li>OAuth clients must be owned by the tailnet, and not by an individual user.</li>\n<li>An OAuth access token expires after 1 hour—this time cannot be modified.</li>\n</ul>\n<p><img src=\"https://cdn.brandfetch.io/tailscale.com/fallback/lettermark/theme/dark/h/256/w/256/icon?c=1bfwsmEH20zzEfSNTed\" alt=\"Project Logo\"></p>\n<p>Ask AI</p>\n<p>reCAPTCHA</p>\n<p>Recaptcha requires verification.</p>\n<p>protected by <strong>reCAPTCHA</strong></p>\n"}