mirror of
https://github.com/calmh/ptsidp.git
synced 2026-07-17 01:35:09 +00:00
No description
- Go 97.1%
- Go Template 2.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| .github/workflows | ||
| chart/ptsidp | ||
| internal/idp | ||
| .ko.yaml | ||
| go.mod | ||
| go.sum | ||
| main.go | ||
| README.md | ||
ptsidp
Proxied Tailscale IDP.
Authentication
Identity comes entirely from the headers the Tailscale ingress proxy injects:
| Header | Mapped to |
|---|---|
Tailscale-User-Login |
sub, email, preferred_username |
Tailscale-User-Name |
name |
Tailscale-User-Profile-Pic |
picture |
email_verified is reported true only when the login looks like an email
address. To change this mapping, edit internal/idp/user.go.
Configuration
| Variable | Default | Description |
|---|---|---|
LISTEN_ADDR |
:8080 |
Address to listen on (plain HTTP). |
ISSUER |
(derived) | Public issuer URL. If unset, derived from X-Forwarded-Proto/X-Forwarded-Host. |
CLIENTS |
(none) | JSON array of registered clients (see below). Only these clients are accepted. |
Clients
CLIENTS is a JSON array. Each client has an id, an optional secret, and a
list of allowed redirectURIs:
[
{
"id": "web",
"secret": "topsecret",
"redirectURIs": ["https://app.example.com/callback"]
},
{
"id": "spa",
"redirectURIs": ["https://spa.example.com/*"]
}
]
- A client with a secret is confidential and authenticates at the token
endpoint via
client_secret_basicorclient_secret_post. - A client without a secret is public: it must use the authorisation code
flow with PKCE (
code_challengeat authorise,code_verifierat token), and presenting a secret is rejected. redirectURIsare enforced. Theredirect_urirequest parameter must match one of them, and the same value must be presented again at the token endpoint. A*is a wildcard matching any run of characters, e.g.https://app.example.com/*. The match is anchored at both ends, so include the trailing slash (/*) to avoid matching look-alike hosts such asapp.example.com.evil.com.
With no clients configured, every authorisation request is rejected.
Running locally
go run .
# In another terminal:
curl -s localhost:8080/.well-known/openid-configuration | jq
When ISSUER is unset the issuer is derived from X-Forwarded-* headers, and
locally you can simulate both the issuer and a Tailscale identity by hand:
# Start with a registered client, e.g.
# CLIENTS='[{"id":"demo","secret":"secret","redirectURIs":["https://client.example.com/cb"]}]' go run .
curl -s \
-H 'X-Forwarded-Proto: https' \
-H 'X-Forwarded-Host: ptsidp.example-tailnet.ts.net' \
-H 'Tailscale-User-Login: alice@example.com' \
-H 'Tailscale-User-Name: Alice Example' \
'localhost:8080/authorize?response_type=code&client_id=demo&scope=openid&redirect_uri=https://client.example.com/cb&state=xyz'