detached 4a0fe8f

docs: update auth documentation for token-only mode

commit
4a0fe8feb83ed03eb6d10a2ea288aadb50b0dcfe
author
brice · · 2026-03-22 06:37 UTC
committer
brice · · 2026-03-22 17:35 UTC
parent
8d39436
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
5 files · +165 -119
M docs/cli/auth.md +39 -75
@@ -1,6 +1,6 @@
11 # Authentication Commands
22
3-Manage Gordon server authentication tokens and passwords.
3+Manage Gordon server authentication tokens.
44
55 ## gordon auth
66
@@ -12,14 +12,13 @@ Manage Gordon server authentication tokens and passwords.
1212 | `token generate` | Generate a new JWT token |
1313 | `token list` | List all stored tokens |
1414 | `token revoke` | Revoke a token by ID (use `--all` to revoke all tokens) |
15-| `password hash` | Generate bcrypt password hash |
1615 | `internal` | Show internal registry credentials |
1716
1817 ---
1918
2019 ## gordon auth login
2120
22-Authenticate with a remote Gordon server using password authentication or a pre-generated token.
21+Authenticate with a remote Gordon server using a pre-generated token.
2322
2423 ```bash
2524 gordon auth login [options]
@@ -30,34 +29,22 @@ gordon auth login [options]
3029 | Option | Description |
3130 |--------|-------------|
3231 | `-r, --remote` | Remote to authenticate with (defaults to active remote) |
33-| `-u, --username` | Username for authentication |
34-| `-p, --password` | Password for authentication |
3532 | `-t, --token` | Authentication token to store for the remote |
3633
3734 ### Description
3835
39-This command prompts for your username and password, authenticates with the remote server's `/auth/password` endpoint, and stores the returned token. When [pass](https://www.passwordstore.org/) is available, the token is stored encrypted at `gordon/remotes/<name>/token` and any plaintext token fields are cleared from `remotes.toml`. When `pass` is unavailable, the token is stored in plaintext in `remotes.toml` with a warning.
36+This command stores a pre-generated token for use with a remote Gordon server. When [pass](https://www.passwordstore.org/) is available, the token is stored encrypted at `gordon/remotes/<name>/token` and any plaintext token fields are cleared from `remotes.toml`. When `pass` is unavailable, the token is stored in plaintext in `remotes.toml` with a warning.
4037
41-If you provide `--token`, the token is stored directly and verified against `/admin/status` on a best-effort basis.
42-
43-The token is a long-lived JWT (7 days) that's used for subsequent CLI operations against the remote.
44-
45-> **Note:** For token-only servers, you can pass `--token` here or use `gordon remotes set-token`.
38+The token is verified against `/admin/status` on a best-effort basis.
4639
4740 ### Examples
4841
4942 ```bash
50-# Login using active remote
51-gordon auth login
52-
53-# Login to specific remote
54-gordon auth login --remote prod
55-
56-# Pre-fill username
57-gordon auth login --username admin
58-
59-# Store a pre-generated token
43+# Store a token for the active remote
6044 gordon auth login --token <token>
45+
46+# Store a token for a specific remote
47+gordon auth login --remote prod --token <token>
6148 ```
6249
6350 ### Output
@@ -65,26 +52,14 @@ gordon auth login --token <token>
6552 When `pass` is available:
6653
6754 ```text
68-Username: admin
69-Password: ********
70-Authenticating with prod...
71-
72-✓ Authentication successful!
7355 Token stored in pass for remote 'prod'
74-Expires in: 604800 seconds
7556 ```
7657
7758 When `pass` is not available:
7859
7960 ```text
80-Username: admin
81-Password: ********
82-Authenticating with prod...
83-
8461 Warning: 'pass' not available. Storing token in plaintext config. Consider installing pass (https://www.passwordstore.org/) for secure token storage.
85-✓ Authentication successful!
8662 Token stored for remote 'prod'
87-Expires in: 604800 seconds
8863 ```
8964
9065 ---
@@ -121,6 +96,18 @@ Compound durations are also supported: `1y6M`, `2w3d`, `1d12h`
12196
12297 Standard Go durations also work: `24h`, `30m`, `1h30m`
12398
99+### Scopes
100+
101+Registry scopes: `push`, `pull`, `push,pull`
102+
103+Admin scopes: `admin:*:*`, `admin:routes:read`, `admin:routes:write`, `admin:config:read`, `admin:config:write`, `admin:status:read`, `admin:secrets:read`, `admin:secrets:write`
104+
105+Combine scopes with commas:
106+
107+```bash
108+gordon auth token generate --subject admin --scopes "push,pull,admin:*:*" --expiry 0
109+```
110+
124111 ### Examples
125112
126113 ```bash
@@ -136,8 +123,11 @@ gordon auth token generate --subject builder --scopes push --expiry 1y
136123 # Temporary token (24 hours)
137124 gordon auth token generate --subject temp --expiry 24h
138125
139-# Token for 6 months
140-gordon auth token generate --subject deploy --expiry 6M
126+# Full admin access token
127+gordon auth token generate --subject admin --scopes "push,pull,admin:*:*" --expiry 6M
128+
129+# Read-only admin token
130+gordon auth token generate --subject monitor --scopes "admin:status:read" --expiry 30d
141131 ```
142132
143133 ### Output
@@ -199,33 +189,6 @@ Token a1b2c3d4-e5f6-7890-abcd-ef1234567890 has been revoked.
199189
200190 ---
201191
202-## gordon auth password hash
203-
204-Generate a bcrypt hash for password authentication.
205-
206-```bash
207-gordon auth password hash
208-```
209-
210-Interactively prompts for a password and outputs the bcrypt hash.
211-
212-### Output
213-
214-```
215-Enter password: ********
216-
217-Bcrypt hash (store in your secrets backend):
218-$2a$10$N9qo8uLOickgx2ZMRZoMye...
219-
220-Then reference the path in your config:
221- [auth]
222- username = "deploy"
223- password_hash = "gordon/auth/password_hash"
224- token_secret = "gordon/auth/token_secret"
225-```
226-
227----
228-
229192 ## gordon auth internal
230193
231194 Display the auto-generated internal registry credentials.
@@ -272,6 +235,14 @@ Usage:
272235 | `push` | Push images to registry |
273236 | `pull` | Pull images from registry |
274237 | `push,pull` | Both push and pull (default) |
238+| `admin:*:*` | Full admin access |
239+| `admin:routes:read` | Read-only routes access |
240+| `admin:routes:write` | Routes write access |
241+| `admin:config:read` | Read-only config access |
242+| `admin:config:write` | Config write access |
243+| `admin:status:read` | Read-only status/health |
244+| `admin:secrets:read` | List secret keys |
245+| `admin:secrets:write` | Set/delete secrets |
275246
276247 ## Token Expiry Formats
277248
@@ -293,8 +264,8 @@ Usage:
293264 gordon auth token generate --subject ci-bot --scopes push,pull --expiry 0
294265
295266 # Save token as CI secret
296-# GitHub: Settings → Secrets → New repository secret
297-# GitLab: Settings → CI/CD → Variables
267+# GitHub: Settings > Secrets > New repository secret
268+# GitLab: Settings > CI/CD > Variables
298269 ```
299270
300271 ### Docker Login
@@ -319,17 +290,9 @@ gordon auth token generate --subject ci-bot --expiry 0
319290 gordon auth token revoke <old-token-id>
320291 ```
321292
322-### Password Setup
293+### Token-only Setup
323294
324295 ```bash
325-# Generate hash
326-gordon auth password hash
327-# Enter: mypassword
328-
329-# Store in pass
330-pass insert gordon/auth/password_hash
331-# Paste: $2a$10$...
332-
333296 # Create token secret
334297 pass insert gordon/auth/token_secret
335298 # Enter a random 32+ character string
@@ -338,9 +301,10 @@ pass insert gordon/auth/token_secret
338301 [auth]
339302 enabled = true
340303 secrets_backend = "pass"
341-username = "deploy"
342-password_hash = "gordon/auth/password_hash"
343304 token_secret = "gordon/auth/token_secret"
305+
306+# Generate a deploy token
307+gordon auth token generate --subject deploy --scopes "push,pull" --expiry 0
344308 ```
345309
346310 ## Related
@@ -1,6 +1,6 @@
1 # Authentication Commands1 # Authentication Commands
2 2
3-Manage Gordon server authentication tokens and passwords.3+Manage Gordon server authentication tokens.
4 4
5 ## gordon auth5 ## gordon auth
6 6
@@ -12,14 +12,13 @@ Manage Gordon server authentication tokens and passwords.
12 | `token generate` | Generate a new JWT token |12 | `token generate` | Generate a new JWT token |
13 | `token list` | List all stored tokens |13 | `token list` | List all stored tokens |
14 | `token revoke` | Revoke a token by ID (use `--all` to revoke all tokens) |14 | `token revoke` | Revoke a token by ID (use `--all` to revoke all tokens) |
15-| `password hash` | Generate bcrypt password hash |
16 | `internal` | Show internal registry credentials |15 | `internal` | Show internal registry credentials |
17 16
18 ---17 ---
19 18
20 ## gordon auth login19 ## gordon auth login
21 20
22-Authenticate with a remote Gordon server using password authentication or a pre-generated token.21+Authenticate with a remote Gordon server using a pre-generated token.
23 22
24 ```bash23 ```bash
25 gordon auth login [options]24 gordon auth login [options]
@@ -30,34 +29,22 @@ gordon auth login [options]
30 | Option | Description |29 | Option | Description |
31 |--------|-------------|30 |--------|-------------|
32 | `-r, --remote` | Remote to authenticate with (defaults to active remote) |31 | `-r, --remote` | Remote to authenticate with (defaults to active remote) |
33-| `-u, --username` | Username for authentication |
34-| `-p, --password` | Password for authentication |
35 | `-t, --token` | Authentication token to store for the remote |32 | `-t, --token` | Authentication token to store for the remote |
36 33
37 ### Description34 ### Description
38 35
39-This command prompts for your username and password, authenticates with the remote server's `/auth/password` endpoint, and stores the returned token. When [pass](https://www.passwordstore.org/) is available, the token is stored encrypted at `gordon/remotes/<name>/token` and any plaintext token fields are cleared from `remotes.toml`. When `pass` is unavailable, the token is stored in plaintext in `remotes.toml` with a warning.36+This command stores a pre-generated token for use with a remote Gordon server. When [pass](https://www.passwordstore.org/) is available, the token is stored encrypted at `gordon/remotes/<name>/token` and any plaintext token fields are cleared from `remotes.toml`. When `pass` is unavailable, the token is stored in plaintext in `remotes.toml` with a warning.
40 37
41-If you provide `--token`, the token is stored directly and verified against `/admin/status` on a best-effort basis.38+The token is verified against `/admin/status` on a best-effort basis.
42-
43-The token is a long-lived JWT (7 days) that's used for subsequent CLI operations against the remote.
44-
45-> **Note:** For token-only servers, you can pass `--token` here or use `gordon remotes set-token`.
46 39
47 ### Examples40 ### Examples
48 41
49 ```bash42 ```bash
50-# Login using active remote43+# Store a token for the active remote
51-gordon auth login
52-
53-# Login to specific remote
54-gordon auth login --remote prod
55-
56-# Pre-fill username
57-gordon auth login --username admin
58-
59-# Store a pre-generated token
60 gordon auth login --token <token>44 gordon auth login --token <token>
45+
46+# Store a token for a specific remote
47+gordon auth login --remote prod --token <token>
61 ```48 ```
62 49
63 ### Output50 ### Output
@@ -65,26 +52,14 @@ gordon auth login --token <token>
65 When `pass` is available:52 When `pass` is available:
66 53
67 ```text54 ```text
68-Username: admin
69-Password: ********
70-Authenticating with prod...
71-
72-✓ Authentication successful!
73 Token stored in pass for remote 'prod'55 Token stored in pass for remote 'prod'
74-Expires in: 604800 seconds
75 ```56 ```
76 57
77 When `pass` is not available:58 When `pass` is not available:
78 59
79 ```text60 ```text
80-Username: admin
81-Password: ********
82-Authenticating with prod...
83-
84 Warning: 'pass' not available. Storing token in plaintext config. Consider installing pass (https://www.passwordstore.org/) for secure token storage.61 Warning: 'pass' not available. Storing token in plaintext config. Consider installing pass (https://www.passwordstore.org/) for secure token storage.
85-✓ Authentication successful!
86 Token stored for remote 'prod'62 Token stored for remote 'prod'
87-Expires in: 604800 seconds
88 ```63 ```
89 64
90 ---65 ---
@@ -121,6 +96,18 @@ Compound durations are also supported: `1y6M`, `2w3d`, `1d12h`
121 96
122 Standard Go durations also work: `24h`, `30m`, `1h30m`97 Standard Go durations also work: `24h`, `30m`, `1h30m`
123 98
99+### Scopes
100+
101+Registry scopes: `push`, `pull`, `push,pull`
102+
103+Admin scopes: `admin:*:*`, `admin:routes:read`, `admin:routes:write`, `admin:config:read`, `admin:config:write`, `admin:status:read`, `admin:secrets:read`, `admin:secrets:write`
104+
105+Combine scopes with commas:
106+
107+```bash
108+gordon auth token generate --subject admin --scopes "push,pull,admin:*:*" --expiry 0
109+```
110+
124 ### Examples111 ### Examples
125 112
126 ```bash113 ```bash
@@ -136,8 +123,11 @@ gordon auth token generate --subject builder --scopes push --expiry 1y
136 # Temporary token (24 hours)123 # Temporary token (24 hours)
137 gordon auth token generate --subject temp --expiry 24h124 gordon auth token generate --subject temp --expiry 24h
138 125
139-# Token for 6 months126+# Full admin access token
140-gordon auth token generate --subject deploy --expiry 6M127+gordon auth token generate --subject admin --scopes "push,pull,admin:*:*" --expiry 6M
128+
129+# Read-only admin token
130+gordon auth token generate --subject monitor --scopes "admin:status:read" --expiry 30d
141 ```131 ```
142 132
143 ### Output133 ### Output
@@ -199,33 +189,6 @@ Token a1b2c3d4-e5f6-7890-abcd-ef1234567890 has been revoked.
199 189
200 ---190 ---
201 191
202-## gordon auth password hash
203-
204-Generate a bcrypt hash for password authentication.
205-
206-```bash
207-gordon auth password hash
208-```
209-
210-Interactively prompts for a password and outputs the bcrypt hash.
211-
212-### Output
213-
214-```
215-Enter password: ********
216-
217-Bcrypt hash (store in your secrets backend):
218-$2a$10$N9qo8uLOickgx2ZMRZoMye...
219-
220-Then reference the path in your config:
221- [auth]
222- username = "deploy"
223- password_hash = "gordon/auth/password_hash"
224- token_secret = "gordon/auth/token_secret"
225-```
226-
227----
228-
229 ## gordon auth internal192 ## gordon auth internal
230 193
231 Display the auto-generated internal registry credentials.194 Display the auto-generated internal registry credentials.
@@ -272,6 +235,14 @@ Usage:
272 | `push` | Push images to registry |235 | `push` | Push images to registry |
273 | `pull` | Pull images from registry |236 | `pull` | Pull images from registry |
274 | `push,pull` | Both push and pull (default) |237 | `push,pull` | Both push and pull (default) |
238+| `admin:*:*` | Full admin access |
239+| `admin:routes:read` | Read-only routes access |
240+| `admin:routes:write` | Routes write access |
241+| `admin:config:read` | Read-only config access |
242+| `admin:config:write` | Config write access |
243+| `admin:status:read` | Read-only status/health |
244+| `admin:secrets:read` | List secret keys |
245+| `admin:secrets:write` | Set/delete secrets |
275 246
276 ## Token Expiry Formats247 ## Token Expiry Formats
277 248
@@ -293,8 +264,8 @@ Usage:
293 gordon auth token generate --subject ci-bot --scopes push,pull --expiry 0264 gordon auth token generate --subject ci-bot --scopes push,pull --expiry 0
294 265
295 # Save token as CI secret266 # Save token as CI secret
296-# GitHub: Settings → Secrets → New repository secret267+# GitHub: Settings > Secrets > New repository secret
297-# GitLab: Settings → CI/CD → Variables268+# GitLab: Settings > CI/CD > Variables
298 ```269 ```
299 270
300 ### Docker Login271 ### Docker Login
@@ -319,17 +290,9 @@ gordon auth token generate --subject ci-bot --expiry 0
319 gordon auth token revoke <old-token-id>290 gordon auth token revoke <old-token-id>
320 ```291 ```
321 292
322-### Password Setup293+### Token-only Setup
323 294
324 ```bash295 ```bash
325-# Generate hash
326-gordon auth password hash
327-# Enter: mypassword
328-
329-# Store in pass
330-pass insert gordon/auth/password_hash
331-# Paste: $2a$10$...
332-
333 # Create token secret296 # Create token secret
334 pass insert gordon/auth/token_secret297 pass insert gordon/auth/token_secret
335 # Enter a random 32+ character string298 # Enter a random 32+ character string
@@ -338,9 +301,10 @@ pass insert gordon/auth/token_secret
338 [auth]301 [auth]
339 enabled = true302 enabled = true
340 secrets_backend = "pass"303 secrets_backend = "pass"
341-username = "deploy"
342-password_hash = "gordon/auth/password_hash"
343 token_secret = "gordon/auth/token_secret"304 token_secret = "gordon/auth/token_secret"
305+
306+# Generate a deploy token
307+gordon auth token generate --subject deploy --scopes "push,pull" --expiry 0
344 ```308 ```
345 309
346 ## Related310 ## Related
M docs/config/auth.md +24 -40
@@ -4,29 +4,18 @@ Configure authentication for the Gordon registry and Admin API.
44
55 Authentication is enabled by default. Gordon will not start without a valid `token_secret` (or `GORDON_AUTH_TOKEN_SECRET`).
66
7-## Pick a Mode
7+## Configuration
88
9-### Token-only (recommended for CI/CD)
9+Gordon uses token-only authentication. All registry and Admin API access is controlled through JWT tokens.
1010
1111 ```toml
1212 [auth]
1313 secrets_backend = "pass"
1414 token_secret = "gordon/auth/token_secret"
1515 token_expiry = "30d"
16+access_token_ttl = "15m"
1617 ```
1718
18-### Password + Token (interactive + CI/CD)
19-
20-```toml
21-[auth]
22-secrets_backend = "pass"
23-username = "deploy"
24-password_hash = "gordon/auth/password_hash"
25-token_secret = "gordon/auth/token_secret"
26-```
27-
28-Token auth always works. Adding `username` + `password_hash` enables interactive login.
29-
3019 ## Options
3120
3221 | Option | Type | Default | Description |
@@ -35,12 +24,11 @@ Token auth always works. Adding `username` + `password_hash` enables interactive
3524 | `secrets_backend` | string | `"unsafe"` | Secrets backend: `"pass"`, `"sops"`, or `"unsafe"` |
3625 | `token_secret` | string | - | **Required.** Path to JWT signing secret in secrets backend |
3726 | `token_expiry` | string | `"30d"` | Token validity duration (0 = never expires) |
38-| `username` | string | - | Username for password auth (optional) |
39-| `password_hash` | string | - | Path to bcrypt hash in secrets backend (optional) |
27+| `access_token_ttl` | string | `"15m"` | Lifetime of ephemeral access tokens issued by `/auth/token` |
4028
4129 ## Secrets Backends
4230
43-`token_secret` and `password_hash` are read through the configured backend:
31+`token_secret` is read through the configured backend:
4432
4533 | Backend | Description |
4634 | --------- | ------------- |
@@ -52,7 +40,7 @@ See [Secret Providers](./secrets.md) for setup details.
5240
5341 ## Environment Variable
5442
55-`GORDON_AUTH_TOKEN_SECRET` overrides `token_secret` in the config. If you don’t set the env var, `token_secret` is loaded from the configured secrets backend (including `pass`).
43+`GORDON_AUTH_TOKEN_SECRET` overrides `token_secret` in the config. If you don't set the env var, `token_secret` is loaded from the configured secrets backend (including `pass`).
5644
5745 ```bash
5846 export GORDON_AUTH_TOKEN_SECRET="your-32-character-secret-here"
@@ -61,8 +49,6 @@ gordon serve
6149
6250 ## Setup
6351
64-### Token-only setup
65-
6652 ```bash
6753 # Create token secret (random 32+ characters)
6854 pass insert gordon/auth/token_secret
@@ -76,28 +62,9 @@ gordon auth token generate --subject ci-bot --scopes push,pull --expiry 0
7662 docker login -u ci-bot -p <token> registry.mydomain.com
7763 ```
7864
79-### Password + token setup
80-
81-```bash
82-# Generate bcrypt hash
83-gordon auth password hash
84-
85-# Store hash and token secret
86-pass insert gordon/auth/password_hash
87-pass insert gordon/auth/token_secret
88-```
89-
90-```bash
91-# Docker registry access
92-docker login -u deploy -p <password> registry.mydomain.com
93-
94-# Remote CLI login (stores a token for you)
95-gordon auth login --remote prod
96-```
97-
9865 ## Remote CLI Tokens
9966
100-If you already have a token (token-only servers), store it directly:
67+Store a token for remote CLI access:
10168
10269 ```bash
10370 gordon auth login --token <token>
@@ -136,6 +103,23 @@ gordon auth token generate --subject builder --scopes push --expiry 0
136103 gordon auth token generate --subject admin --scopes "push,pull,admin:*:*" --expiry 0
137104 ```
138105
106+## Access Token TTL
107+
108+The `access_token_ttl` setting controls the lifetime of ephemeral access tokens issued by the `/auth/token` endpoint. These short-lived tokens are used internally for registry operations and Admin API sessions.
109+
110+| Value | Meaning |
111+|-------|---------|
112+| `"15m"` | 15 minutes (default) |
113+| `"30m"` | 30 minutes |
114+| `"1h"` | 1 hour (maximum before store validation applies) |
115+
116+Tokens with a lifetime of 1 hour or less skip store validation for performance. Longer-lived tokens (generated via `gordon auth token generate`) are always validated against the token store.
117+
118+```toml
119+[auth]
120+access_token_ttl = "30m"
121+```
122+
139123 ## Token Expiry
140124
141125 Durations support `d`, `w`, `M`, `y` and combinations like `1y6M` or `2w3d`.
@@ -4,29 +4,18 @@ Configure authentication for the Gordon registry and Admin API.
4 4
5 Authentication is enabled by default. Gordon will not start without a valid `token_secret` (or `GORDON_AUTH_TOKEN_SECRET`).5 Authentication is enabled by default. Gordon will not start without a valid `token_secret` (or `GORDON_AUTH_TOKEN_SECRET`).
6 6
7-## Pick a Mode7+## Configuration
8 8
9-### Token-only (recommended for CI/CD)9+Gordon uses token-only authentication. All registry and Admin API access is controlled through JWT tokens.
10 10
11 ```toml11 ```toml
12 [auth]12 [auth]
13 secrets_backend = "pass"13 secrets_backend = "pass"
14 token_secret = "gordon/auth/token_secret"14 token_secret = "gordon/auth/token_secret"
15 token_expiry = "30d"15 token_expiry = "30d"
16+access_token_ttl = "15m"
16 ```17 ```
17 18
18-### Password + Token (interactive + CI/CD)
19-
20-```toml
21-[auth]
22-secrets_backend = "pass"
23-username = "deploy"
24-password_hash = "gordon/auth/password_hash"
25-token_secret = "gordon/auth/token_secret"
26-```
27-
28-Token auth always works. Adding `username` + `password_hash` enables interactive login.
29-
30 ## Options19 ## Options
31 20
32 | Option | Type | Default | Description |21 | Option | Type | Default | Description |
@@ -35,12 +24,11 @@ Token auth always works. Adding `username` + `password_hash` enables interactive
35 | `secrets_backend` | string | `"unsafe"` | Secrets backend: `"pass"`, `"sops"`, or `"unsafe"` |24 | `secrets_backend` | string | `"unsafe"` | Secrets backend: `"pass"`, `"sops"`, or `"unsafe"` |
36 | `token_secret` | string | - | **Required.** Path to JWT signing secret in secrets backend |25 | `token_secret` | string | - | **Required.** Path to JWT signing secret in secrets backend |
37 | `token_expiry` | string | `"30d"` | Token validity duration (0 = never expires) |26 | `token_expiry` | string | `"30d"` | Token validity duration (0 = never expires) |
38-| `username` | string | - | Username for password auth (optional) |27+| `access_token_ttl` | string | `"15m"` | Lifetime of ephemeral access tokens issued by `/auth/token` |
39-| `password_hash` | string | - | Path to bcrypt hash in secrets backend (optional) |
40 28
41 ## Secrets Backends29 ## Secrets Backends
42 30
43-`token_secret` and `password_hash` are read through the configured backend:31+`token_secret` is read through the configured backend:
44 32
45 | Backend | Description |33 | Backend | Description |
46 | --------- | ------------- |34 | --------- | ------------- |
@@ -52,7 +40,7 @@ See [Secret Providers](./secrets.md) for setup details.
52 40
53 ## Environment Variable41 ## Environment Variable
54 42
55-`GORDON_AUTH_TOKEN_SECRET` overrides `token_secret` in the config. If you don’t set the env var, `token_secret` is loaded from the configured secrets backend (including `pass`).43+`GORDON_AUTH_TOKEN_SECRET` overrides `token_secret` in the config. If you don't set the env var, `token_secret` is loaded from the configured secrets backend (including `pass`).
56 44
57 ```bash45 ```bash
58 export GORDON_AUTH_TOKEN_SECRET="your-32-character-secret-here"46 export GORDON_AUTH_TOKEN_SECRET="your-32-character-secret-here"
@@ -61,8 +49,6 @@ gordon serve
61 49
62 ## Setup50 ## Setup
63 51
64-### Token-only setup
65-
66 ```bash52 ```bash
67 # Create token secret (random 32+ characters)53 # Create token secret (random 32+ characters)
68 pass insert gordon/auth/token_secret54 pass insert gordon/auth/token_secret
@@ -76,28 +62,9 @@ gordon auth token generate --subject ci-bot --scopes push,pull --expiry 0
76 docker login -u ci-bot -p <token> registry.mydomain.com62 docker login -u ci-bot -p <token> registry.mydomain.com
77 ```63 ```
78 64
79-### Password + token setup
80-
81-```bash
82-# Generate bcrypt hash
83-gordon auth password hash
84-
85-# Store hash and token secret
86-pass insert gordon/auth/password_hash
87-pass insert gordon/auth/token_secret
88-```
89-
90-```bash
91-# Docker registry access
92-docker login -u deploy -p <password> registry.mydomain.com
93-
94-# Remote CLI login (stores a token for you)
95-gordon auth login --remote prod
96-```
97-
98 ## Remote CLI Tokens65 ## Remote CLI Tokens
99 66
100-If you already have a token (token-only servers), store it directly:67+Store a token for remote CLI access:
101 68
102 ```bash69 ```bash
103 gordon auth login --token <token>70 gordon auth login --token <token>
@@ -136,6 +103,23 @@ gordon auth token generate --subject builder --scopes push --expiry 0
136 gordon auth token generate --subject admin --scopes "push,pull,admin:*:*" --expiry 0103 gordon auth token generate --subject admin --scopes "push,pull,admin:*:*" --expiry 0
137 ```104 ```
138 105
106+## Access Token TTL
107+
108+The `access_token_ttl` setting controls the lifetime of ephemeral access tokens issued by the `/auth/token` endpoint. These short-lived tokens are used internally for registry operations and Admin API sessions.
109+
110+| Value | Meaning |
111+|-------|---------|
112+| `"15m"` | 15 minutes (default) |
113+| `"30m"` | 30 minutes |
114+| `"1h"` | 1 hour (maximum before store validation applies) |
115+
116+Tokens with a lifetime of 1 hour or less skip store validation for performance. Longer-lived tokens (generated via `gordon auth token generate`) are always validated against the token store.
117+
118+```toml
119+[auth]
120+access_token_ttl = "30m"
121+```
122+
139 ## Token Expiry123 ## Token Expiry
140 124
141 Durations support `d`, `w`, `M`, `y` and combinations like `1y6M` or `2w3d`.125 Durations support `d`, `w`, `M`, `y` and combinations like `1y6M` or `2w3d`.
M docs/config/reference.md +2 -3
@@ -28,9 +28,7 @@ enabled = true # Enable registry authentication (d
2828 secrets_backend = "unsafe" # "pass", "sops", or "unsafe"
2929 token_secret = "" # Path in secrets backend to JWT signing key (REQUIRED)
3030 token_expiry = "720h" # Token expiry duration (720h = 30 days)
31-# Optional: enable password authentication (for interactive login)
32-# username = "" # Username for password auth
33-# password_hash = "" # Path in secrets backend to bcrypt hash
31+access_token_ttl = "15m" # Ephemeral access token lifetime (default: 15m)
3432
3533 # =============================================================================
3634 # API (applies to both Registry and Admin endpoints)
@@ -182,6 +180,7 @@ keep_last = 3 # Keep N newest tags per repository
182180 | `auth.enabled` | `true` | Enable authentication; when `false`, run local-only mode (loopback-only `/v2/*`, `/admin/*` disabled) |
183181 | `auth.secrets_backend` | `"unsafe"` | Secrets storage |
184182 | `auth.token_expiry` | `"720h"` | 30 days |
183+| `auth.access_token_ttl` | `"15m"` | Ephemeral access token lifetime |
185184 | `api.rate_limit.enabled` | `true` | Enable rate limiting |
186185 | `api.rate_limit.global_rps` | `500` | Global requests/second |
187186 | `api.rate_limit.per_ip_rps` | `50` | Per-IP requests/second |
@@ -28,9 +28,7 @@ enabled = true # Enable registry authentication (d
28 secrets_backend = "unsafe" # "pass", "sops", or "unsafe"28 secrets_backend = "unsafe" # "pass", "sops", or "unsafe"
29 token_secret = "" # Path in secrets backend to JWT signing key (REQUIRED)29 token_secret = "" # Path in secrets backend to JWT signing key (REQUIRED)
30 token_expiry = "720h" # Token expiry duration (720h = 30 days)30 token_expiry = "720h" # Token expiry duration (720h = 30 days)
31-# Optional: enable password authentication (for interactive login)31+access_token_ttl = "15m" # Ephemeral access token lifetime (default: 15m)
32-# username = "" # Username for password auth
33-# password_hash = "" # Path in secrets backend to bcrypt hash
34 32
35 # =============================================================================33 # =============================================================================
36 # API (applies to both Registry and Admin endpoints)34 # API (applies to both Registry and Admin endpoints)
@@ -182,6 +180,7 @@ keep_last = 3 # Keep N newest tags per repository
182 | `auth.enabled` | `true` | Enable authentication; when `false`, run local-only mode (loopback-only `/v2/*`, `/admin/*` disabled) |180 | `auth.enabled` | `true` | Enable authentication; when `false`, run local-only mode (loopback-only `/v2/*`, `/admin/*` disabled) |
183 | `auth.secrets_backend` | `"unsafe"` | Secrets storage |181 | `auth.secrets_backend` | `"unsafe"` | Secrets storage |
184 | `auth.token_expiry` | `"720h"` | 30 days |182 | `auth.token_expiry` | `"720h"` | 30 days |
183+| `auth.access_token_ttl` | `"15m"` | Ephemeral access token lifetime |
185 | `api.rate_limit.enabled` | `true` | Enable rate limiting |184 | `api.rate_limit.enabled` | `true` | Enable rate limiting |
186 | `api.rate_limit.global_rps` | `500` | Global requests/second |185 | `api.rate_limit.global_rps` | `500` | Global requests/second |
187 | `api.rate_limit.per_ip_rps` | `50` | Per-IP requests/second |186 | `api.rate_limit.per_ip_rps` | `50` | Per-IP requests/second |
M docs/getting-started.md +1 -1
@@ -132,7 +132,7 @@ gordon auth token generate --subject deploy --scopes push,pull --expiry 0
132132
133133 `--expiry 0` creates a non-expiring token. Prefer a finite expiry and a rotation policy unless you explicitly need a long-lived deploy token.
134134
135-Save this token securely - you'll use it with `gordon --remote` (or a saved remote), and it should be limited to remote deploy use.
135+Save this token securely -- you will use it to authenticate with your Gordon server from CI/CD pipelines and remote CLI sessions.
136136
137137 ## 8. Deploy Your First App
138138
@@ -132,7 +132,7 @@ gordon auth token generate --subject deploy --scopes push,pull --expiry 0
132 132
133 `--expiry 0` creates a non-expiring token. Prefer a finite expiry and a rotation policy unless you explicitly need a long-lived deploy token.133 `--expiry 0` creates a non-expiring token. Prefer a finite expiry and a rotation policy unless you explicitly need a long-lived deploy token.
134 134
135-Save this token securely - you'll use it with `gordon --remote` (or a saved remote), and it should be limited to remote deploy use.135+Save this token securely -- you will use it to authenticate with your Gordon server from CI/CD pipelines and remote CLI sessions.
136 136
137 ## 8. Deploy Your First App137 ## 8. Deploy Your First App
138 138
M docs/upgrading.md +99 -0
@@ -2,6 +2,105 @@
22
33 This guide covers breaking changes and migration steps between major versions.
44
5+## v2.7.0 to v2.8.0
6+
7+### Breaking: Password Authentication Removed
8+
9+Gordon v2.8.0 removes password-based authentication entirely. Only token-based authentication is supported.
10+
11+**What changed:**
12+
13+- `auth.type = "password"` is no longer accepted
14+- `auth.password` and `auth.password_hash` config fields are removed
15+- The `gordon auth password hash` CLI command is removed
16+- The `gordon auth login` command no longer accepts `--username` or `--password` flags
17+- The `/auth/password` endpoint is removed
18+
19+**New features:**
20+
21+- `auth.access_token_ttl` configures the lifetime of ephemeral access tokens issued by `/auth/token` (default: `"15m"`)
22+- Admin scopes (`admin:*:*`, `admin:routes:read`, etc.) allow fine-grained access control for remote CLI operations
23+
24+**Migration steps:**
25+
26+1. **Before upgrading**, generate a token on your current Gordon instance:
27+
28+ ```bash
29+ gordon auth token generate --subject deploy --scopes "push,pull,admin:*:*" --expiry 0
30+ ```
31+
32+ Save this token securely. You will need it after upgrading.
33+
34+2. **Update remotes** to use the generated token:
35+
36+ ```bash
37+ gordon auth login --token <token>
38+ # or
39+ gordon remotes set-token prod <token>
40+ ```
41+
42+3. **Update your config** to remove password fields:
43+
44+ **Before (v2.7.0):**
45+ ```toml
46+ [auth]
47+ enabled = true
48+ secrets_backend = "pass"
49+ username = "deploy"
50+ password_hash = "gordon/auth/password_hash"
51+ token_secret = "gordon/auth/token_secret"
52+ ```
53+
54+ **After (v2.8.0):**
55+ ```toml
56+ [auth]
57+ enabled = true
58+ secrets_backend = "pass"
59+ token_secret = "gordon/auth/token_secret"
60+ access_token_ttl = "15m"
61+ ```
62+
63+4. **Update CI/CD pipelines** to use `GORDON_TOKEN` environment variable for authentication. See the [deployment guides](./deployment/index.md).
64+
65+5. **Upgrade the binary** and restart:
66+
67+ ```bash
68+ curl -fsSL https://gordon.bnema.dev/install | bash
69+ systemctl --user restart gordon
70+ ```
71+
72+6. **Verify** the server starts without errors:
73+
74+ ```bash
75+ journalctl --user -u gordon -f
76+ ```
77+
78+### New: Configurable Access Token TTL
79+
80+Ephemeral access tokens issued by `/auth/token` now have a configurable lifetime via `auth.access_token_ttl`. The default is `"15m"`. Tokens with a lifetime of 1 hour or less skip store validation for performance.
81+
82+```toml
83+[auth]
84+access_token_ttl = "30m"
85+```
86+
87+### New: Admin Scopes
88+
89+Tokens can now include fine-grained admin scopes for remote CLI operations:
90+
91+```bash
92+# Full admin access
93+gordon auth token generate --subject admin --scopes "push,pull,admin:*:*" --expiry 0
94+
95+# Read-only monitoring
96+gordon auth token generate --subject monitor --scopes "admin:status:read" --expiry 30d
97+
98+# CI deploy with route read + config write
99+gordon auth token generate --subject ci --scopes "push,pull,admin:routes:read,admin:config:write" --expiry 0
100+```
101+
102+See [Token Scopes](./config/auth.md#token-scopes) for the full list.
103+
5104 ## v2.6.0 to v2.7.0
6105
7106 ### Breaking: Token Secret Required
@@ -2,6 +2,105 @@
2 2
3 This guide covers breaking changes and migration steps between major versions.3 This guide covers breaking changes and migration steps between major versions.
4 4
5+## v2.7.0 to v2.8.0
6+
7+### Breaking: Password Authentication Removed
8+
9+Gordon v2.8.0 removes password-based authentication entirely. Only token-based authentication is supported.
10+
11+**What changed:**
12+
13+- `auth.type = "password"` is no longer accepted
14+- `auth.password` and `auth.password_hash` config fields are removed
15+- The `gordon auth password hash` CLI command is removed
16+- The `gordon auth login` command no longer accepts `--username` or `--password` flags
17+- The `/auth/password` endpoint is removed
18+
19+**New features:**
20+
21+- `auth.access_token_ttl` configures the lifetime of ephemeral access tokens issued by `/auth/token` (default: `"15m"`)
22+- Admin scopes (`admin:*:*`, `admin:routes:read`, etc.) allow fine-grained access control for remote CLI operations
23+
24+**Migration steps:**
25+
26+1. **Before upgrading**, generate a token on your current Gordon instance:
27+
28+ ```bash
29+ gordon auth token generate --subject deploy --scopes "push,pull,admin:*:*" --expiry 0
30+ ```
31+
32+ Save this token securely. You will need it after upgrading.
33+
34+2. **Update remotes** to use the generated token:
35+
36+ ```bash
37+ gordon auth login --token <token>
38+ # or
39+ gordon remotes set-token prod <token>
40+ ```
41+
42+3. **Update your config** to remove password fields:
43+
44+ **Before (v2.7.0):**
45+ ```toml
46+ [auth]
47+ enabled = true
48+ secrets_backend = "pass"
49+ username = "deploy"
50+ password_hash = "gordon/auth/password_hash"
51+ token_secret = "gordon/auth/token_secret"
52+ ```
53+
54+ **After (v2.8.0):**
55+ ```toml
56+ [auth]
57+ enabled = true
58+ secrets_backend = "pass"
59+ token_secret = "gordon/auth/token_secret"
60+ access_token_ttl = "15m"
61+ ```
62+
63+4. **Update CI/CD pipelines** to use `GORDON_TOKEN` environment variable for authentication. See the [deployment guides](./deployment/index.md).
64+
65+5. **Upgrade the binary** and restart:
66+
67+ ```bash
68+ curl -fsSL https://gordon.bnema.dev/install | bash
69+ systemctl --user restart gordon
70+ ```
71+
72+6. **Verify** the server starts without errors:
73+
74+ ```bash
75+ journalctl --user -u gordon -f
76+ ```
77+
78+### New: Configurable Access Token TTL
79+
80+Ephemeral access tokens issued by `/auth/token` now have a configurable lifetime via `auth.access_token_ttl`. The default is `"15m"`. Tokens with a lifetime of 1 hour or less skip store validation for performance.
81+
82+```toml
83+[auth]
84+access_token_ttl = "30m"
85+```
86+
87+### New: Admin Scopes
88+
89+Tokens can now include fine-grained admin scopes for remote CLI operations:
90+
91+```bash
92+# Full admin access
93+gordon auth token generate --subject admin --scopes "push,pull,admin:*:*" --expiry 0
94+
95+# Read-only monitoring
96+gordon auth token generate --subject monitor --scopes "admin:status:read" --expiry 30d
97+
98+# CI deploy with route read + config write
99+gordon auth token generate --subject ci --scopes "push,pull,admin:routes:read,admin:config:write" --expiry 0
100+```
101+
102+See [Token Scopes](./config/auth.md#token-scopes) for the full list.
103+
5 ## v2.6.0 to v2.7.0104 ## v2.6.0 to v2.7.0
6 105
7 ### Breaking: Token Secret Required106 ### Breaking: Token Secret Required

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close