Skip to content

Commit 31f3d3b

Browse files
authored
Merge pull request #100 from gotify/oidc
OIDC Documentation
2 parents cf61685 + 62a7c1e commit 31f3d3b

6 files changed

Lines changed: 358 additions & 17 deletions

File tree

.vitepress/config.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ export default defineConfig({
4242
items: [
4343
{text: 'Intro to Gotify Plugins', link: '/docs/plugin'},
4444
{text: 'Writing Plugins', link: '/docs/plugin-write'},
45-
{text: 'Building and Deploying Plugins', link: '/docs/plugin-deploy'},
45+
{
46+
text: 'Building and Deploying Plugins',
47+
link: '/docs/plugin-deploy',
48+
},
4649
],
4750
},
4851
{
@@ -54,8 +57,11 @@ export default defineConfig({
5457
],
5558
},
5659
{
57-
text: 'Miscellaneous',
60+
text: 'Guides',
5861
items: [
62+
{text: 'OpenID Connect (OIDC)', link: '/docs/oidc'},
63+
{text: 'Session Elevation', link: '/docs/session-elevation'},
64+
{text: 'Migrate to 3.x', link: '/docs/migrate-to-3'},
5965
{text: 'Apache reverse proxy', link: '/docs/apache'},
6066
{text: 'Caddy 2 reverse proxy', link: '/docs/caddy'},
6167
{text: 'Haproxy reverse proxy', link: '/docs/haproxy'},

config.data.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {createMarkdownRenderer} from 'vitepress';
2+
3+
const SOURCE = 'https://raw.githubusercontent.com/gotify/server/master/gotify-server.env.example';
4+
5+
const uncomment = (line: string): string => line.replace(/^#( ?)/, '');
6+
const codeBlock = (text: string) => '```\n' + text.trimEnd() + '\n```';
7+
8+
const renderSetting = (block: string[]): string => {
9+
const assignment = block.find((l) => /^[A-Z][A-Z0-9_]*=/.test(uncomment(l)));
10+
if (!assignment) throw Error('could not find assignment ' + block);
11+
12+
const name = uncomment(assignment).split('=')[0];
13+
return ['### ' + name, codeBlock(block.join('\n'))].join('\n\n');
14+
};
15+
16+
export default {
17+
async load() {
18+
const res = await fetch(SOURCE);
19+
if (!res.ok) throw Error('could not fetch gotify-server.env.example');
20+
21+
const [header, ...blocks] = (await res.text())
22+
.trimEnd()
23+
.split(/\n *\n/)
24+
.map((b) => b.split('\n'))
25+
.filter((b) => b.some((l) => l.trim()));
26+
27+
const markdown = [
28+
codeBlock(header.map(uncomment).join('\n')),
29+
...blocks.map(renderSetting),
30+
].join('\n\n');
31+
32+
return (await createMarkdownRenderer('.')).render(markdown);
33+
},
34+
};

docs/config.md

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Configuration
22

3+
<script setup>
4+
import {data as envExample} from '../config.data.ts'
5+
</script>
6+
7+
::: details 3.x Config
8+
9+
Gotify 3.x is configured through environment variables, which can be loaded from
10+
an env file. [`gotify-server.env.example`](https://raw.githubusercontent.com/gotify/server/refs/heads/master/gotify-server.env.example)
11+
12+
<div v-html="envExample"></div>
13+
14+
:::
15+
16+
::: details 2.x Config
17+
318
gotify/server can be configured per config file and environment variables.
419
When using docker it is recommended to use environment variables.
520

@@ -40,33 +55,46 @@ server:
4055
enabled: false # if the certificate should be requested from letsencrypt
4156
accepttos: false # if you accept the tos from letsencrypt
4257
cache: data/certs # the directory of the cache from letsencrypt
58+
directoryurl: # override the directory url of the ACME server
59+
# Let's Encrypt highly recommend testing against their staging environment before using their production environment.
60+
# Staging server has high rate limits for testing and debugging, issued certificates are not valid
61+
# example: https://acme-staging-v02.api.letsencrypt.org/directory
4362
hosts: # the hosts for which letsencrypt should request certificates
44-
# - mydomain.tld
45-
# - myotherdomain.tld
63+
# - mydomain.tld
64+
# - myotherdomain.tld
4665
responseheaders: # response headers are added to every response (default: none)
47-
# X-Custom-Header: "custom value"
66+
# X-Custom-Header: "custom value"
67+
4868
trustedproxies: # IPs or IP ranges of trusted proxies. Used to obtain the remote ip via the X-Forwarded-For header. (configure 127.0.0.1 to trust sockets)
49-
# - 127.0.0.1
50-
# - 192.168.178.0/24
69+
# - 127.0.0.1/32
5170
# - ::1
71+
securecookie: false # If the secure flag should be set on cookies. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie#secure
5272

5373
cors: # Sets cors headers only when needed and provides support for multiple allowed origins. Overrides Access-Control-* Headers in response headers.
5474
alloworigins:
55-
# - ".+.example.com"
56-
# - "otherdomain.com"
75+
# - ".+.example.com"
76+
# - "otherdomain.com"
5777
allowmethods:
58-
# - "GET"
59-
# - "POST"
78+
# - "GET"
79+
# - "POST"
6080
allowheaders:
61-
# - "Authorization"
62-
# - "content-type"
63-
81+
# - "Authorization"
82+
# - "content-type"
6483
stream:
6584
pingperiodseconds: 45 # the interval in which websocket pings will be sent. Only change this value if you know what you are doing.
66-
allowedorigins: # allowed origins for websocket connections (same origin is always allowed, default only same origin)
85+
allowedorigins: # allowed origins for websocket connections (same origin is always allowed)
6786
# - ".+.example.com"
6887
# - "otherdomain.com"
69-
database: # see below
88+
oidc:
89+
enabled: false # Enable OpenID Connect login, allowing users to authenticate via an external identity provider (e.g. Keycloak, Authelia, Google).
90+
issuer: # The OIDC issuer URL. This is the base URL of your identity provider, used to discover endpoints. Example: "https://auth.example.com/realms/myrealm"
91+
clientid: # The client ID registered with your identity provider for this application.
92+
clientsecret: # The client secret for the registered client.
93+
redirecturl: http://gotify.example.org/auth/oidc/callback # The callback URL that the identity provider redirects to after authentication. Must match exactly what is configured in your identity provider.
94+
autoregister: true # If true, automatically create a new user on first OIDC login. If false, only existing users can log in via OIDC.
95+
usernameclaim: preferred_username # The OIDC claim used to determine the username. Common values: "preferred_username" or "email".
96+
97+
database: # for database see (configure database section)
7098
dialect: sqlite3
7199
connection: data/gotify.db
72100
defaultuser: # on database creation, gotify creates an admin user (these values will only be used for the first start, if you want to edit the user after the first start use the WebUI)
@@ -118,7 +146,8 @@ GOTIFY_SERVER_SSL_CERTFILE=
118146
GOTIFY_SERVER_SSL_CERTKEY=
119147
GOTIFY_SERVER_SSL_LETSENCRYPT_ENABLED=false
120148
GOTIFY_SERVER_SSL_LETSENCRYPT_ACCEPTTOS=false
121-
GOTIFY_SERVER_SSL_LETSENCRYPT_CACHE=certs
149+
GOTIFY_SERVER_SSL_LETSENCRYPT_CACHE=data/certs
150+
GOTIFY_SERVER_SSL_LETSENCRYPT_DIRECTORYURL=
122151
# GOTIFY_SERVER_SSL_LETSENCRYPT_HOSTS=[mydomain.tld, myotherdomain.tld]
123152
# GOTIFY_SERVER_RESPONSEHEADERS={X-Custom-Header: "custom value", x-other: value}
124153
# GOTIFY_SERVER_TRUSTEDPROXIES=[127.0.0.1,192.168.178.2/24]
@@ -127,6 +156,7 @@ GOTIFY_SERVER_SSL_LETSENCRYPT_CACHE=certs
127156
# GOTIFY_SERVER_CORS_ALLOWHEADERS=[X-Gotify-Key, Authorization]
128157
# GOTIFY_SERVER_STREAM_ALLOWEDORIGINS=[.+.example\.com, otherdomain\.com]
129158
GOTIFY_SERVER_STREAM_PINGPERIODSECONDS=45
159+
GOTIFY_SERVER_SECURECOOKIE=false
130160
GOTIFY_DATABASE_DIALECT=sqlite3
131161
GOTIFY_DATABASE_CONNECTION=data/gotify.db
132162
GOTIFY_DEFAULTUSER_NAME=admin
@@ -135,4 +165,13 @@ GOTIFY_PASSSTRENGTH=10
135165
GOTIFY_UPLOADEDIMAGESDIR=data/images
136166
GOTIFY_PLUGINSDIR=data/plugins
137167
GOTIFY_REGISTRATION=false
168+
GOTIFY_OIDC_ENABLED=false
169+
GOTIFY_OIDC_ISSUER=
170+
GOTIFY_OIDC_CLIENTID=
171+
GOTIFY_OIDC_CLIENTSECRET=
172+
GOTIFY_OIDC_REDIRECTURL=http://gotify.example.org/auth/oidc/callback
173+
GOTIFY_OIDC_AUTOREGISTER=true
174+
GOTIFY_OIDC_USERNAMECLAIM=preferred_username
138175
```
176+
177+
:::

docs/migrate-to-3.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Migrate to 3.x
2+
3+
- The `config.yml` file is no longer supported, convert it to the new env format
4+
with [`migrate-config`](#migrating-your-config).
5+
- If you set list or map environment variables, their syntax changed, see
6+
[List and map syntax](#list-and-map-syntax).
7+
- If you have scripts hitting client-token endpoints, they may now need
8+
[elevation](#adapting-your-scripts).
9+
10+
## Config Changes
11+
12+
### YAML config file removed
13+
14+
The YAML config file (`config.yml`) is no longer supported. Gotify can now be
15+
only configured by environment variables, which can be loaded from an env file.
16+
The first existing file from this search order is loaded:
17+
18+
1. `gotify-server.env` (in the working directory)
19+
2. `$XDG_CONFIG_HOME/gotify/gotify-server.env` (`$XDG_CONFIG_HOME` falls back to `$HOME/.config` when unset)
20+
3. `/etc/gotify/server.env`
21+
22+
See the [Configuration](/docs/config) page for the full list of variables.
23+
24+
### Migrating your config
25+
26+
The `migrate-config` command converts an existing `config.yml` to the new env
27+
format. It prints the result to stdout.
28+
29+
```bash
30+
$ gotify-server migrate-config config.yml > gotify-server.env
31+
```
32+
33+
With Docker:
34+
35+
```bash
36+
$ docker run --rm -v "$(pwd)/config.yml:/app/config.yml" gotify/server \
37+
migrate-config config.yml > gotify-server.env
38+
```
39+
40+
### Environment List and map syntax
41+
42+
Defining settings via environment variables was already possible, but the syntax
43+
for list and map values has changed. If you set any of the variables below, update
44+
their format.
45+
46+
**Lists** are now comma-separated instead of a YAML array:
47+
48+
- `GOTIFY_SERVER_TRUSTEDPROXIES`
49+
- `GOTIFY_SERVER_CORS_ALLOWORIGINS`
50+
- `GOTIFY_SERVER_CORS_ALLOWMETHODS`
51+
- `GOTIFY_SERVER_CORS_ALLOWHEADERS`
52+
- `GOTIFY_SERVER_STREAM_ALLOWEDORIGINS`
53+
- `GOTIFY_SERVER_SSL_LETSENCRYPT_HOSTS`
54+
- `GOTIFY_OIDC_SCOPES`
55+
56+
```bash
57+
# before
58+
GOTIFY_SERVER_TRUSTEDPROXIES=[127.0.0.1/32, ::1]
59+
# after
60+
GOTIFY_SERVER_TRUSTEDPROXIES=127.0.0.1/32,::1
61+
```
62+
63+
**Maps** are now a JSON object instead of a YAML map:
64+
65+
- `GOTIFY_SERVER_RESPONSEHEADERS`
66+
67+
```bash
68+
# before
69+
GOTIFY_SERVER_RESPONSEHEADERS={X-Custom-Header: "custom value"}
70+
# after
71+
GOTIFY_SERVER_RESPONSEHEADERS={"X-Custom-Header":"custom value"}
72+
```
73+
74+
## API Changes
75+
76+
Introduces step-up authentication via time-limited [session
77+
elevation](./session-elevation.md). A session/client token must re-authenticate
78+
before sensitive, hard-to-undo actions.
79+
80+
HTTP Basic auth and application tokens are unaffected.
81+
82+
### Endpoints that now require elevation
83+
84+
With a non-elevated client token these return `403`:
85+
86+
| Endpoint | Action |
87+
| :-------------------------------------------- | :----------------------------- |
88+
| `POST /current/user/password` | Change current user's password |
89+
| `DELETE /client/{id}` | Delete a client |
90+
| `DELETE /application/{id}` | Delete an application |
91+
| `POST /client/{id}/elevate` | Elevate a client token |
92+
| `GET /user`, `GET`/`POST`/`DELETE /user/{id}` | Manage users (admin) |
93+
94+
The `Client` and `CurrentUser` models have gotten elevation-related fields. See the
95+
[API documentation](/api-docs) for details.
96+
97+
### Adapting your scripts
98+
99+
Scripts that hit the endpoints above with a client token now need that token to
100+
be elevated. Either:
101+
102+
- Use HTTP Basic auth as they are elevated by default.
103+
- Elevate the client in the WebUI or the api with basic auth.
104+
105+
## CLI Changes
106+
107+
The binary now uses subcommands. You should migrate to using the `serve`
108+
subcommand. For backwards compatibility running gotify without a command will
109+
continue to serve the server.
110+
111+
```bash
112+
$ ./gotify-linux-amd64 serve
113+
```
114+
115+
The Docker image already defaults to `serve`, so `docker run` and Docker Compose
116+
setups keep working unchanged.

docs/oidc.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# OpenID Connect (OIDC)
2+
3+
[[toc]]
4+
5+
Gotify supports OpenID Connect for Single Sign-On (SSO), allowing users to authenticate via an external identity provider such as Authelia or Dex.
6+
7+
::: warning
8+
The identity provider **must** support [PKCE](https://oauth.net/2/pkce/) (Proof Key for Code Exchange). IdPs without PKCE support are currently unsupported.
9+
:::
10+
11+
## Configuration
12+
13+
| Variable | Description |
14+
| :----------------------------- | :--------------------------------------------------------------------------------------------------------- |
15+
| `GOTIFY_OIDC_ENABLED` | Enable OIDC login. |
16+
| `GOTIFY_OIDC_ISSUER` | The OIDC issuer URL. Used to discover endpoints via `/.well-known/openid-configuration`. |
17+
| `GOTIFY_OIDC_CLIENTID` | The client ID registered with your identity provider. |
18+
| `GOTIFY_OIDC_CLIENTSECRET` | The client secret. |
19+
| `GOTIFY_OIDC_REDIRECTURL` | The callback URL the identity provider redirects to after authentication. Must match your provider config. |
20+
| `GOTIFY_OIDC_AUTOREGISTER` | Automatically create a new Gotify user on first OIDC login. |
21+
| `GOTIFY_OIDC_USERNAMECLAIM` | The OIDC claim used to determine the username. Common values: `preferred_username` or `email`. |
22+
| `GOTIFY_OIDC_LINK_BY_USERNAME` | Link an OIDC identity to an existing local user with the same username. Disabled by default. |
23+
| `GOTIFY_OIDC_SCOPES` | Comma-separated scopes to request. Defaults to `openid,profile,email`. |
24+
25+
```bash
26+
GOTIFY_OIDC_ENABLED=true
27+
GOTIFY_OIDC_ISSUER=https://auth.example.org
28+
GOTIFY_OIDC_CLIENTID=gotify
29+
GOTIFY_OIDC_CLIENTSECRET=YOUR_CLIENT_SECRET
30+
GOTIFY_OIDC_REDIRECTURL=https://gotify.example.org/auth/oidc/callback
31+
GOTIFY_OIDC_AUTOREGISTER=true
32+
GOTIFY_OIDC_USERNAMECLAIM=preferred_username
33+
GOTIFY_OIDC_LINK_BY_USERNAME=false
34+
GOTIFY_OIDC_SCOPES=openid,profile,email
35+
```
36+
37+
See the [Configuration](/docs/config) page for the full config reference.
38+
39+
### Redirect URL
40+
41+
- The redirect URL must always end with `/auth/oidc/callback`.
42+
- If Gotify is served at the root, the redirect URL is `https://gotify.example.org/auth/oidc/callback`.
43+
- If Gotify is served on a sub-path (e.g. behind a reverse proxy at `/gotify/`), the sub-path must be included: `https://example.org/gotify/auth/oidc/callback`.
44+
- For the **Android app** to support OIDC login, you must add `gotify://oidc/callback` as an additional redirect URL in your identity provider's client configuration.
45+
46+
This URL must match **exactly** between the Gotify config and your identity provider's client configuration.
47+
48+
## Linking by username
49+
50+
Gotify identifies users by username. When the OIDC username claim clashes with an existing local user that is not yet bound to an OIDC identity, this login is rejected by default. Set `GOTIFY_OIDC_LINK_BY_USERNAME=true` to bind OIDC identities to existing local users.
51+
52+
Only enable it if you trust that usernames in your identity provider map to the same people as your Gotify usernames.
53+
54+
## Sample IdP Config
55+
56+
### Authelia
57+
58+
[Authelia](https://www.authelia.com/) is a self-hosted authentication and authorization server.
59+
60+
::: details Authelia configuration (configuration.yml)
61+
62+
```yml
63+
identity_providers:
64+
oidc:
65+
clients:
66+
- client_id: 'gotify'
67+
client_name: 'gotify'
68+
client_secret: '$pbkdf2-sha512$310000$...' # generate with: authelia crypto hash generate pbkdf2
69+
public: false
70+
authorization_policy: 'two_factor'
71+
require_pkce: true
72+
pkce_challenge_method: 'S256'
73+
consent_mode: implicit
74+
redirect_uris:
75+
- 'https://gotify.example.org/auth/oidc/callback' # See redirect url docs
76+
- 'gotify://oidc/callback' # Required for Android app OIDC login
77+
scopes:
78+
- 'openid'
79+
- 'profile'
80+
- 'email'
81+
response_types:
82+
- 'code'
83+
grant_types:
84+
- 'authorization_code'
85+
access_token_signed_response_alg: 'none'
86+
userinfo_signed_response_alg: 'none'
87+
token_endpoint_auth_method: 'client_secret_basic'
88+
```
89+
90+
:::
91+
92+
### Dex
93+
94+
[Dex](https://dexidp.io/) is a federated OpenID Connect provider.
95+
96+
::: details Dex configuration
97+
98+
```yml
99+
staticClients:
100+
- id: gotify
101+
redirectURIs:
102+
- 'https://gotify.example.org/auth/oidc/callback' # See redirect url docs
103+
- 'gotify://oidc/callback' # Required for Android app OIDC login
104+
name: 'Gotify'
105+
secret: secret
106+
```
107+
108+
:::

0 commit comments

Comments
 (0)