From 7be12991adef69320079aee56830952cb3cc8229 Mon Sep 17 00:00:00 2001 From: Arun Philip Date: Wed, 8 Apr 2026 12:20:26 -0400 Subject: [PATCH] feat: improve OAuth client secret support with --advertise-tags flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add --advertise-tags CLI flag (also reads TS_ADVERTISE_TAGS env var) - Update README with required OAuth scope: Auth Keys → Write Signed-off-by: Arun Philip --- README.md | 47 ++++++++++++++++++++++++++++------------------- tsidp-server.go | 5 +++-- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 1cc8df1d2..3c482b69c 100644 --- a/README.md +++ b/README.md @@ -53,13 +53,21 @@ Once tsidp has started, visit `https://idp.yourtailnet.ts.net` in a browser to c > If you're running tsidp for the first time it may take a few minutes for the TLS certificate to generate. You may not be able to access the service until the certificate is ready. > [!NOTE] -> As an alternative to traditional auth keys, you can use OAuth client secrets for authentication by passing them through `TS_AUTHKEY`. +> **Using OAuth Client Secrets** > -> When using OAuth client secrets: -> - Pass the OAuth client secret through `TS_AUTHKEY` (same as regular auth keys) -> - Specify advertise tags using `TS_ADVERTISE_TAGS` -> - The OAuth client secret must start with `tskey-client-` -> - The tags must be properly configured in your Tailscale ACL policy +> As an alternative to traditional auth keys, you can use OAuth client secrets for automatic node registration. +> +> **Setup:** +> 1. In the [Tailscale admin console](https://login.tailscale.com/admin/settings/oauth), create an OAuth client with **Auth Keys → Write** scope +> 2. Ensure the advertise tag (e.g. `tag:tsidp`) is defined in your ACL `tagOwners` +> 3. Set `TS_AUTHKEY` to your OAuth client secret (`tskey-client-...`) +> 4. Set `TS_ADVERTISE_TAGS` (or `--advertise-tags`) — **required** when using OAuth client secrets +> +> ```yaml +> environment: +> - TS_AUTHKEY=tskey-client-xxxxx +> - TS_ADVERTISE_TAGS=tag:tsidp +> ``` ### Other Ways to Build and Run @@ -146,18 +154,19 @@ $ TAILSCALE_USE_WIP_CODE=1 TS_AUTHKEY={YOUR_TAILSCALE_AUTHKEY} TSNET_FORCE_LOGIN The `tsidp-server` is configured by several command-line flags: -| Flag | Description | Default | -| ----------------------- | -------------------------------------------------------------------------------------------------- | -------- | -| `-dir ` | Directory path to save tsnet and tsidp state. Recommend to be set. | `""` | -| `-hostname ` | hostname on tailnet. Will become `.your-tailnet.ts.net` | `idp` | -| `-port ` | Port to listen on | `443` | -| `-local-port ` | Listen on `localhost:`. Useful for testing | disabled | -| `-use-local-tailscaled` | Use local tailscaled instead of tsnet | `false` | -| `-funnel` | Use Tailscale Funnel to make tsidp available on the public internet so it works with SaaS products | disabled | -| `-enable-sts` | Enable OAuth token exchange using RFC 8693 | disabled | -| `-log ` | Set logging level: `debug`, `info`, `warn`, `error` | `info` | -| `-debug-all-requests` | For development. Prints all requests and responses | disabled | -| `-debug-tsnet` | For development. Enables debug level logging with tsnet connection | disabled | +| Flag | Description | Default | +| ------------------------------ | -------------------------------------------------------------------------------------------------- | -------- | +| `-dir ` | Directory path to save tsnet and tsidp state. Recommend to be set. | `""` | +| `-hostname ` | hostname on tailnet. Will become `.your-tailnet.ts.net` | `idp` | +| `-port ` | Port to listen on | `443` | +| `-local-port ` | Listen on `localhost:`. Useful for testing | disabled | +| `-use-local-tailscaled` | Use local tailscaled instead of tsnet | `false` | +| `-funnel` | Use Tailscale Funnel to make tsidp available on the public internet so it works with SaaS products | disabled | +| `-enable-sts` | Enable OAuth token exchange using RFC 8693 | disabled | +| `-advertise-tags ` | Comma-separated advertise tags (e.g. `tag:tsidp`). Required when using OAuth client secrets | `""` | +| `-log ` | Set logging level: `debug`, `info`, `warn`, `error` | `info` | +| `-debug-all-requests` | For development. Prints all requests and responses | disabled | +| `-debug-tsnet` | For development. Enables debug level logging with tsnet connection | disabled | ### CLI Environment Variables @@ -197,7 +206,7 @@ The Docker image exposes the CLI flags through environment variables. If omitted | `TSIDP_DEBUG_TSNET=1` | `-debug-tsnet` | | `TSIDP_DEBUG_ALL_REQUESTS=1` | `-debug-all-requests` | | `TS_AUTHKEY=` | _(env var only)_ | -| `TS_ADVERTISE_TAGS=` | _(env var only)_ | +| `TS_ADVERTISE_TAGS=` | `-advertise-tags ` | ## Application Configuration Guides (WIP) diff --git a/tsidp-server.go b/tsidp-server.go index 4e769fe49..2d1173c47 100644 --- a/tsidp-server.go +++ b/tsidp-server.go @@ -44,6 +44,7 @@ var ( flagHostname = flag.String("hostname", cmp.Or(envknob.String("TS_HOSTNAME"), "idp"), "tsnet hostname to use instead of idp") flagDir = flag.String("dir", envknob.String("TS_STATE_DIR"), "tsnet state directory; a default one will be created if not provided") flagEnableSTS = flag.Bool("enable-sts", envknob.Bool("TSIDP_ENABLE_STS"), "enable OIDC STS token exchange support") + flagAdvertiseTags = flag.String("advertise-tags", envknob.String("TS_ADVERTISE_TAGS"), "comma-separated advertise tags (e.g. tag:tsidp,tag:server); required when using OAuth client secrets") // application logging levels flagLogLevel = flag.String("log", cmp.Or(envknob.String("TSIDP_LOG"), "info"), "log levels: debug, info, warn, error") @@ -127,8 +128,8 @@ func main() { Dir: *flagDir, } - if advertiseTags := os.Getenv("TS_ADVERTISE_TAGS"); advertiseTags != "" { - tags := strings.Split(advertiseTags, ",") + if *flagAdvertiseTags != "" { + tags := strings.Split(*flagAdvertiseTags, ",") for i, tag := range tags { tags[i] = strings.TrimSpace(tag) }