You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -241,37 +242,6 @@ If Authelia uses a self-signed cert, Dashy's server has to trust it before it ca
241
242
Everything should now be fully configured and working 🎉
242
243
When you load Dashy, you'll be redirected to Authelia's login page. After signing in, you'll land back on Dashy's homepage with full access, and all of Dashy's client, server and asset endpoints will be locked behind authentication.
243
244
244
-
### Silent token renewal (optional)
245
-
246
-
By default, when your token expires Dashy sends you back through Authelia's login to get a new one. Set `enableSilentRenew: true` to have Dashy refresh the session quietly in the background instead, using a refresh token:
247
-
248
-
```yaml
249
-
oidc:
250
-
clientId: dashy
251
-
endpoint: https://authelia.lvh.me:9091
252
-
adminGroup: admins
253
-
scope: openid profile email groups
254
-
enableSilentRenew: true
255
-
```
256
-
257
-
Dashy adds the `offline_access` scope to its request automatically, but Authelia only issues a refresh token if the client is allowed to. Add `offline_access` to the client's `scopes` and `refresh_token` to its `grant_types`:
258
-
259
-
```yaml
260
-
clients:
261
-
- client_id: dashy
262
-
scopes:
263
-
- openid
264
-
- profile
265
-
- email
266
-
- groups
267
-
- offline_access
268
-
grant_types:
269
-
- authorization_code
270
-
- refresh_token
271
-
```
272
-
273
-
It's off by default, and if a refresh ever fails Dashy falls back to the normal sign-in. See [silent token renewal](../authentication.md#silent-token-renewal) for the full notes and caveats.
274
-
275
245
---
276
246
277
247
## 4. Groups and Visibility
@@ -304,6 +274,41 @@ sections:
304
274
groups: ['interns']
305
275
```
306
276
277
+
---
278
+
279
+
280
+
## 5. Silent token renewal (optional)
281
+
282
+
By default, when your token expires Dashy sends you back through Authelia's login to get a new one. Set `enableSilentRenew: true` to have Dashy refresh the session quietly in the background instead, using a refresh token:
283
+
284
+
```yaml
285
+
oidc:
286
+
clientId: dashy
287
+
endpoint: https://authelia.lvh.me:9091
288
+
adminGroup: admins
289
+
scope: openid profile email groups
290
+
enableSilentRenew: true
291
+
```
292
+
293
+
Dashy adds the `offline_access` scope to its request automatically, but Authelia only issues a refresh token if the client is allowed to. Add `offline_access` to the client's `scopes` and `refresh_token` to its `grant_types`:
294
+
295
+
```yaml
296
+
clients:
297
+
- client_id: dashy
298
+
scopes:
299
+
- openid
300
+
- profile
301
+
- email
302
+
- groups
303
+
- offline_access
304
+
grant_types:
305
+
- authorization_code
306
+
- refresh_token
307
+
```
308
+
309
+
It's off by default, and if a refresh ever fails Dashy falls back to the normal sign-in. See [silent token renewal](./oidc.md#silent-token-renewal) for the full notes and caveats.
310
+
311
+
307
312
---
308
313
309
314
## Troubleshooting common Authelia Issues
@@ -395,7 +400,7 @@ Boot starts in [`src/main.js`](https://github.com/lissy93/dashy/blob/4.1.5/src/m
395
400
- `loadOidcSettings()`reads `auth.oidc` (or `auth.keycloak`) at boot and returns a normalised `{ issuer, clientId, adminGroup, adminRole }`. For generic OIDC providers the `issuer` is whatever you set as `endpoint` in `conf.yml`, verbatim
396
401
- `createOidcMiddleware()`returns a Connect middleware. Permissive on no-token requests so the SPA can bootstrap; otherwise it verifies the Bearer token against the issuer's JWKS using [`jose`](https://github.com/panva/jose). Checks cover signature, issuer (against the canonical value from the discovery doc), audience (must equal `clientId`), and expiry, with a 30-second clock-skew tolerance. Sets `req.auth = { user, isAdmin, claims }` on success, `401` on failure
397
402
- `getIssuerContext()`lazily fetches `.well-known/openid-configuration` on first use and wraps `jwks_uri` in `createRemoteJWKSet`, which handles JWKS caching and on-demand key rotation. The result is memoised per-issuer for the life of the process
398
-
- `deriveIsAdmin()`checks the token's `groups` claim against `adminGroup`, and the `realm_access.roles` / `resource_access.<clientId>.roles` arrays against `adminRole`. Authelia only emits `groups`, so the group path is what's used in practice
403
+
- `deriveIsAdmin()`checks the token's `groups` claim against `adminGroup`, and the top-level `roles` claim against `adminRole` (for Keycloak it also folds in the nested `realm_access.roles` / `resource_access.<clientId>.roles` arrays). Authelia only emits `groups`, so the group path is what's used in practice
399
404
- `maybeBootstrapConfig()`is the stripped-response helper. When auth is configured, guest access is off, and an unauthenticated request hits the root `/conf.yml`, it returns a minimal copy with only `appConfig.auth`, `appConfig.enableServiceWorker`, and a `pageInfo.title` of `Login | <your title>`. Sections, items, hostnames and any other secrets never leave the server
400
405
401
406
[`services/app.js`](https://github.com/lissy93/dashy/blob/4.1.5/services/app.js) wires it all together. The middleware mounts as `protectConfig` in front of every YAML route and config-mutating route. The `/*.yml` handler sets `Cache-Control: private, no-store` and `Vary: Authorization` whenever auth is configured (so intermediate caches can never mix auth states), then calls `maybeBootstrapConfig`; a stripped result is sent as-is, otherwise `res.sendFile` serves the full file. `POST /config-manager/save` is additionally guarded by `requireAdmin`, which returns `401` if `req.auth` is unset and `403` if `req.auth.isAdmin` is false.
@@ -181,6 +183,24 @@ If you want separate accounts beyond `akadmin`:
181
183
3. On the new user's page, click **Set password**, set a password, click **Update**
182
184
4. Add the user to `dashy-admins` for admin access, or leave them out for a non-admin
183
185
186
+
### Restrict who can access Dashy (optional)
187
+
188
+
By default any Authentik user can sign in to Dashy. To limit access to one or more groups, bind a group policy to the `Dashy` application; Authentik then denies sign-in to anyone outside those groups. This is separate from `adminGroup`, which only controls who gets admin rights inside Dashy, not who can access it at all.
189
+
190
+
1. Go to **Applications > Applications** and open the `Dashy` application
191
+
192
+

193
+
194
+
2. Open the **Policy / Group / User Bindings** tab and click **Bind existing policy**
195
+
196
+

197
+
198
+
3. Switch to the **Group** tab, choose the group that should have access, make sure **Enabled** is on, and click **Create**
199
+
200
+

201
+
202
+
Access is now limited to members of the bound group. Add another binding for each additional group that should be allowed in.
203
+
184
204
### Summary
185
205
186
206
Authentik should now be configured, and ready to go!
@@ -219,21 +239,6 @@ If Authentik runs on a different host or behind a reverse proxy, make sure `endp
219
239
Everything should now be fully configured and working 🎉
220
240
When you load Dashy, you'll be redirected to Authentik's login page. After signing in you will land back on Dashy's homepage with full access, and all of Dashy's client, server and asset endpoints will be locked behind authentication.
221
241
222
-
### Silent token renewal (optional)
223
-
224
-
By default, when your token expires Dashy sends you back through Authentik's login to get a new one. Set `enableSilentRenew: true` to have Dashy refresh the session quietly in the background instead, using a refresh token:
Dashy adds the `offline_access` scope to its request automatically. Authentik ships an `offline_access` scope mapping by default, so just make sure it's listed under the provider's **Advanced protocol settings > Selected Scopes**. It's off by default, and if a refresh ever fails Dashy falls back to the normal sign-in. See [silent token renewal](../authentication.md#silent-token-renewal) for the full notes and caveats.
236
-
237
242
---
238
243
239
244
## 4. Groups and Visibility
@@ -266,6 +271,22 @@ sections:
266
271
groups: ['interns']
267
272
```
268
273
274
+
275
+
## 5. Silent token renewal (optional)
276
+
277
+
By default, when your token expires Dashy sends you back through Authentik's login to get a new one. Set `enableSilentRenew: true` to have Dashy refresh the session quietly in the background instead, using a refresh token:
Dashy adds the `offline_access` scope to its request automatically. Authentik ships an `offline_access` scope mapping by default, so just make sure it's listed under the provider's **Advanced protocol settings > Selected Scopes**. It's off by default, and if a refresh ever fails Dashy falls back to the normal sign-in. See [silent token renewal](./oidc.md#silent-token-renewal) for the full notes and caveats.
289
+
269
290
---
270
291
271
292
## Troubleshooting common Authentik Issues
@@ -349,7 +370,7 @@ Boot starts in [`src/main.js`](https://github.com/lissy93/dashy/blob/4.1.5/src/m
349
370
- `loadOidcSettings()`reads `auth.oidc` (or `auth.keycloak`) at boot and returns a normalised `{ issuer, clientId, adminGroup, adminRole }`. For generic OIDC providers the `issuer` is whatever you set as `endpoint` in `conf.yml`, verbatim
350
371
- `createOidcMiddleware()`returns a Connect middleware. Permissive on no-token requests so the SPA can bootstrap; otherwise it verifies the Bearer token against the issuer's JWKS using [`jose`](https://github.com/panva/jose). Checks cover signature, issuer (against the canonical value from the discovery doc), audience (must equal `clientId`), and expiry, with a 30-second clock-skew tolerance. Sets `req.auth = { user, isAdmin, claims }` on success, `401` on failure
351
372
- `getIssuerContext()`lazily fetches `.well-known/openid-configuration` on first use and wraps `jwks_uri` in `createRemoteJWKSet`, which handles JWKS caching and on-demand key rotation. The result is memoised per-issuer for the life of the process
352
-
- `deriveIsAdmin()`checks the token's `groups` claim against `adminGroup`, and the `realm_access.roles` / `resource_access.<clientId>.roles` arrays against `adminRole`. Authentik only emits `groups`, so the group path is what's used in practice
373
+
- `deriveIsAdmin()`checks the token's `groups` claim against `adminGroup`, and the top-level `roles` claim against `adminRole` (for Keycloak it also folds in the nested `realm_access.roles` / `resource_access.<clientId>.roles` arrays). Authentik only emits `groups`, so the group path is what's used in practice
353
374
- `maybeBootstrapConfig()`is the stripped-response helper. When auth is configured, guest access is off, and an unauthenticated request hits the root `/conf.yml`, it returns a minimal copy with only `appConfig.auth`, `appConfig.enableServiceWorker`, and a `pageInfo.title` of `Login | <your title>`. Sections, items, hostnames and any other secrets never leave the server
354
375
355
376
[`services/app.js`](https://github.com/lissy93/dashy/blob/4.1.5/services/app.js) wires it all together. The middleware mounts as `protectConfig` in front of every YAML route and config-mutating route. The `/*.yml` handler sets `Cache-Control: private, no-store` and `Vary: Authorization` whenever auth is configured (so intermediate caches can never mix auth states), then calls `maybeBootstrapConfig`; a stripped result is sent as-is, otherwise `res.sendFile` serves the full file. `POST /config-manager/save` is additionally guarded by `requireAdmin`, which returns `401` if `req.auth` is unset and `403` if `req.auth.isAdmin` is false.
0 commit comments