This is the full developer documentation for Pocket ID # Introduction > A self-hosted OpenID Connect Certified™ and OAuth 2.0 provider that lets your users sign in to every app you host with a passkey instead of a password. Pocket ID is the one place where your users sign in, for every app you connect to it through OpenID Connect (OIDC). It’s made for small teams, startups and homelabs that find [Keycloak](https://www.keycloak.org) or [Authentik](https://goauthentik.io) too much for what they need. Pocket ID only supports passwordless authentication methods, primarily [passkeys](https://www.passkeys.io), so there are no passwords to reuse, leak or phish. A passkey can live in a password manager, on a phone or on a hardware key such as a YubiKey, and it unlocks with a fingerprint, face scan or PIN. ![The Pocket ID sign-in page with an Authenticate button](/_astro/sign-in-light.BmYIB2Y4_ZB9TJJ.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh)![The Pocket ID sign-in page with an Authenticate button](/_astro/sign-in-dark.BMQETm0H_2p5hB9.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh) You can try it on the [demo instance](https://demo.pocket-id.org). ## How sign-in works [Section titled “How sign-in works”](#how-sign-in-works) Any app that offers sign-in with OpenID Connect, often labeled as SSO, OAuth or OIDC, can use Pocket ID. You register the app in Pocket ID as an **OIDC client**, and the app sends its users to Pocket ID when they sign in. If you are interested in the technical details, the diagram below shows the typical sign-in flow with Pocket ID. No worries though, you don’t have to understand how OIDC and OAuth 2.0 work to use it. The browser carries the user between the app and Pocket ID, while the app fetches the tokens from Pocket ID directly, so both the browser and the app need to reach Pocket ID. Pocket ID only lets a user through when their passkey checks out and, if you restricted the client to some groups, when they’re a member of one of them. The app then receives tokens with the user’s name, email address and groups, and creates its own session from them. Apps without OIDC support, and apps that only support LDAP or SAML, can still sit behind Pocket ID with an authentication proxy, as [Proxy services](/docs/guides/proxy-services) shows. ## Concepts [Section titled “Concepts”](#concepts) * **Users** sign in with their passkeys, and an admin can let a user in once with a **login code**, such as to add their first passkey. * **Groups** decide which users may sign in to which client, and the apps you connect receive them in the token to assign roles. * **OIDC clients** are the apps that use Pocket ID for sign-in, each with its own client ID, secret and callback URLs. * **APIs** are your own backends that accept access tokens from Pocket ID, which you only need for [API access](/docs/guides/apis). This is a more advanced use case. ## Next steps [Section titled “Next steps”](#next-steps) [Install Pocket ID](/docs/setup/installation)Start Pocket ID with Docker Compose or as a single binary. [Put it behind HTTPS](/docs/setup/reverse-proxy)Passkeys only work over HTTPS, so Pocket ID needs a reverse proxy. [Connect your first app](/docs/setup/connect-an-app)Create an OIDC client and give the app the values it asks for. [Client examples](/docs/client-examples)Step-by-step setup for nearly a hundred apps, from Immich to Proxmox. ## Videos [Section titled “Videos”](#videos) * [Use a custom OIDC and passkeys to log in to Tailscale with Pocket ID](https://www.youtube.com/watch?v=sPUkAm7yDlU) by Tailscale * [Improving Security with Hardware Keys - Authentik & Pocket-ID](https://www.youtube.com/watch?v=QC5IUmu7cgw) by Jim’s Garage * [Protect your MCP Server with OAuth 2.1 in just 5 minutes with Pocket ID](https://www.youtube.com/watch?v=JjoXz2u5r3Y) # Connect an app > Create an OIDC client for an app, give the app its client ID, secret and discovery URL, and choose who may sign in. Every app that signs in with Pocket ID is an **OIDC client**. You create the client in Pocket ID, and the app gets three values from it: a client ID, a client secret and the discovery URL. [Client examples](/docs/client-examples) has the exact steps for nearly a hundred apps. This page explains the steps they share, here for [Immich](/docs/client-examples/immich) at `https://photos.example.com`. ## Create the client [Section titled “Create the client”](#create-the-client) 1. Find the app’s **callback URL**, which some apps call the redirect URI. Pocket ID sends users back to it after they signed in, and only to the URLs you list. The app’s OIDC documentation names it, such as `https://photos.example.com/auth/login` for Immich. 2. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. Enter a name, pick the client type and add the callback URL: ![The Create OIDC Client form with the name Immich, the confidential client type and one callback URL](/_astro/oidc-client-create-light.DijFM1W3_Z2PvST.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh)![The Create OIDC Client form with the name Immich, the confidential client type and one callback URL](/_astro/oidc-client-create-dark.DHkVxt3G_Z27hWBk.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh) Most self-hosted apps have a backend, so they’re **confidential clients** that sign their requests with the client secret. Choose **public client** for single-page, mobile and desktop apps, which can’t keep a secret and use PKCE instead. 3. Click **Create**. The client’s page shows the values the app needs: ![The connection details of the Immich client: client ID, client secret, OIDC discovery URL and the individual endpoint URLs](/_astro/oidc-client-details-light.FwYk_TrG_26eKyf.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh)![The connection details of the Immich client: client ID, client secret, OIDC discovery URL and the individual endpoint URLs](/_astro/oidc-client-details-dark.RWQ_u_ZB_asthn.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh) Caution The client secret is only shown now, so copy it before you leave the page. If you lose it, add a new one under **Credentials**. ## Choose who may sign in [Section titled “Choose who may sign in”](#choose-who-may-sign-in) A new client lets nobody in until you choose who may use it. On the client’s **Access** tab, select the groups whose members may sign in, or choose **All Users**: ![The Allowed User Groups card with Selected user groups chosen and the groups Family and Media ticked](/_astro/oidc-client-allowed-groups-light.CCe-H1eT_1nMVHJ.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh)![The Allowed User Groups card with Selected user groups chosen and the groups Family and Media ticked](/_astro/oidc-client-allowed-groups-dark.Ck41MM9__Z16bTiX.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh) Everyone else gets “You are not allowed to access this service” when they try to sign in. [Allowed user groups](/docs/configuration/allowed-groups) has the details. ## Configure the app [Section titled “Configure the app”](#configure-the-app) Enter the values from the client’s page in the app’s OIDC or SSO settings. Apps name the fields differently, but they map like this: | The app asks for | Enter | | ------------------------------------------ | ----------------------------------------------------------------------- | | Issuer, provider URL or authority | `https://id.example.com`, which is your `APP_URL` | | Discovery, well-known or configuration URL | `https://id.example.com/.well-known/openid-configuration` | | Client ID | The **Client ID** | | Client secret | The **Client secret**, or nothing for a public client | | Scopes | `openid profile email`, plus `groups` if the app assigns roles by group | Some apps don’t read the discovery URL and ask for each endpoint instead. **Show more details** on the client’s page lists them, and [Endpoints](#endpoints) below has their paths. The app’s server fetches tokens from Pocket ID directly, so the issuer URL has to work from the app’s container too, not only in your browser. ## Test the sign-in [Section titled “Test the sign-in”](#test-the-sign-in) Sign in to the app with its OIDC or SSO button. The first time you sign in to a client, Pocket ID asks whether to share your details with it: ![The Sign in to Immich page listing the email, profile and groups that Immich wants to access](/_astro/consent-light.BY8hct3o_Zhsx6s.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh)![The Sign in to Immich page listing the email, profile and groups that Immich wants to access](/_astro/consent-dark.CZ_9sGDh_ZFef1I.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh) Pocket ID remembers the answer, and only asks again when the app requests more than before. Users can revoke it under **My Apps**, and you can turn the screen off for trusted clients with **Skip Consent Screen** on the client’s **General** tab. If the sign-in fails, [Common issues](/docs/troubleshooting/common-issues) covers the usual causes, such as a callback URL that doesn’t match. ## Endpoints [Section titled “Endpoints”](#endpoints) Every endpoint is relative to your `APP_URL`, and the discovery document lists them all: | Endpoint | Path | | ----------------------------- | ----------------------------------- | | Discovery | `/.well-known/openid-configuration` | | Authorization | `/authorize` | | Token | `/api/oidc/token` | | Userinfo | `/api/oidc/userinfo` | | Signing keys (JWKS) | `/.well-known/jwks.json` | | End session (logout) | `/api/oidc/end-session` | | Token introspection | `/api/oidc/introspect` | | Device authorization | `/api/oidc/device/authorize` | | Pushed authorization requests | `/api/oidc/par` | The token, userinfo, introspection, JWKS and pushed authorization endpoints use `INTERNAL_APP_URL` instead of `APP_URL` when you set it, for apps that reach Pocket ID at another address than browsers do. [Scopes and claims](/docs/guides/scopes-and-claims) describes what the tokens contain. # Data export and import > Learn how to export and import your Pocket ID data for backup or migration The Pocket ID CLI lets you export and import your Pocket ID data. This is useful when creating backups, moving an installation to another instance, or switching database providers. Caution This feature is experimental and may not work correctly. Please create a backup before importing data and report any issues you encounter. ## Exporting Data [Section titled “Exporting Data”](#exporting-data) Use the `export` command to create a backup file: ```bash pocket-id export --path ./path/to/export.zip ``` ### Exporting to standard output [Section titled “Exporting to standard output”](#exporting-to-standard-output) You can pass `--path -` to write the export to standard output. This is helpful when piping the archive or working with Docker: ```bash pocket-id export --path - > ./path/to/export.zip ``` ### Export with Docker [Section titled “Export with Docker”](#export-with-docker) Exporting to standard output is often the simplest approach when running Pocket ID in Docker: ```bash docker compose exec -T pocket-id ./pocket-id export --path - > ./path/to/export.zip ``` ## Importing Data [Section titled “Importing Data”](#importing-data) 1. Shut down your Pocket ID instance. 2. Use the import command to restore a previously exported archive: ```bash pocket-id import --path ./path/to/export.zip ``` ### Importing from standard input [Section titled “Importing from standard input”](#importing-from-standard-input) Like export, you can use `--path -` to read from standard input: ```bash pocket-id import --yes --path - < ./path/to/export.zip ``` When importing from standard input, you must include `--yes` to confirm the operation without a prompt. The following prompt cannot be shown when reading from standard input: ```plaintext WARNING: This feature is experimental and may not work correctly. Please create a backup before proceeding and report any issues you encounter. WARNING: Import will erase all existing data at the following locations: Database: /app/data/pocket-id.db Uploads Path: /app/data/uploads Do you want to continue? [y/N]: ``` ### Import with Docker [Section titled “Import with Docker”](#import-with-docker) When using Docker, importing from standard input is often the easiest method: ```bash cat ./export.zip | docker compose run -T pocket-id ./pocket-id import --yes --path - ``` The `-T` flag disables TTY allocation. Without it, Docker fails with `the input device is not a TTY` when piping data into the container, and binary output from the export may be corrupted. # Installation > Run Pocket ID with Docker Compose or as a single binary, then create the admin account and its passkey. Pocket ID is a single program with a built-in SQLite database, so one container or one binary is all it needs. HTTPS is required Browsers only allow passkeys on HTTPS pages, or on `localhost` while you try Pocket ID out. Plan for a domain such as `id.example.com` and a [reverse proxy](/docs/setup/reverse-proxy) in front of Pocket ID. ## Install [Section titled “Install”](#install) * Docker Compose 1. Download the Compose file and the example `.env` file: ```bash curl -O https://raw.githubusercontent.com/pocket-id/pocket-id/main/docker-compose.yml curl -o .env https://raw.githubusercontent.com/pocket-id/pocket-id/main/.env.example ``` 2. Set the address you’ll open Pocket ID at and an encryption key in `.env`: .env ```ini APP_URL=https://id.example.com # Generate one with: openssl rand -base64 32 ENCRYPTION_KEY= ``` [Environment variables](/docs/configuration/environment-variables) lists every other option. 3. Start Pocket ID: ```bash docker compose up -d ``` Pocket ID listens on port 1411 and keeps its database and uploads in `./data`. The images are published as `ghcr.io/pocket-id/pocket-id` and `pocketid/pocket-id` on Docker Hub. * Binary 1. Download the binary for your system from the [latest release](https://github.com/pocket-id/pocket-id/releases/latest), named `pocket-id__`, such as `pocket-id_linux_amd64`: ```bash curl -fL -o pocket-id https://github.com/pocket-id/pocket-id/releases/latest/download/pocket-id_linux_amd64 chmod +x pocket-id ``` Releases cover Linux, macOS, Windows, FreeBSD and OpenBSD on amd64 and arm64, and Linux on 386 and armv7. 2. Download the example `.env` file next to the binary and set `APP_URL` and `ENCRYPTION_KEY` in it, as in the Docker Compose steps: ```bash curl -o .env https://raw.githubusercontent.com/pocket-id/pocket-id/main/.env.example ``` 3. Start Pocket ID: ```bash ./pocket-id ``` Pocket ID reads the `.env` file from the directory it runs in, listens on port 1411 and keeps its data in a `data` directory next to it. To run it as a service, start it with systemd or your platform’s equivalent. ## Create the admin account [Section titled “Create the admin account”](#create-the-admin-account) Open `https://id.example.com/setup` and fill in your username, email address and name. ![The Sign Up to Pocket ID page with fields for username, email, first name and last name](/_astro/setup-light.CuSkYVxf_NCcnY.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh)![The Sign Up to Pocket ID page with fields for username, email, first name and last name](/_astro/setup-dark.D16dJ2cv_1hLKDv.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh) After **Sign Up**, Pocket ID asks you to set up a passkey: click **Add Passkey**, since that’s how you sign in from now on. The setup page only works until the first account exists. Next, [connect your first app](/docs/setup/connect-an-app), or [add users](/docs/setup/user-management). ## Offline use [Section titled “Offline use”](#offline-use) Pocket ID makes three kinds of outgoing requests, which you can turn off for air-gapped servers: * `VERSION_CHECK_DISABLED=true` stops the check for new releases on GitHub. * `ANALYTICS_DISABLED=true` stops the daily [heartbeat](/docs/configuration/analytics) that counts running instances. * `ICON_LIBRARY_URL=disabled` stops the icon search for client logos, which loads the [selfh.st icons](https://selfh.st/icons) from jsDelivr. ## Community installation methods [Section titled “Community installation methods”](#community-installation-methods) Caution These methods are maintained by the community, not by the Pocket ID team, and may lag behind releases. ### Podman Quadlet [Section titled “Podman Quadlet”](#podman-quadlet) For rootless Podman, save this as `~/.config/containers/systemd/pocket-id.container`. For rootful Podman, save it in `/etc/containers/systemd/` and change `WantedBy` to `multi-user.target`. pocket-id.container ```ini [Container] Image=ghcr.io/pocket-id/pocket-id:v2 PublishPort=1411:1411 Volume=pocket-id:/app/data:Z # Optional: updates the image automatically, needs podman-auto-update.timer AutoUpdate=registry HealthCmd=/app/pocket-id healthcheck HealthInterval=1m30s HealthTimeout=5s HealthRetries=2 HealthStartPeriod=10s Environment=APP_URL=https://id.example.com # A file with the key, generated with: openssl rand -base64 32 Environment=ENCRYPTION_KEY_FILE=/path/to/encryption_key [Service] Restart=always [Install] WantedBy=default.target ``` ### Proxmox [Section titled “Proxmox”](#proxmox) Run the [community helper script](https://community-scripts.github.io/ProxmoxVE/scripts?id=pocketid) as root in the Proxmox shell: ```bash bash -c "$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/pocketid.sh)" ``` The script installs Pocket ID as a service in `/opt/pocket-id`, with its configuration in `/opt/pocket-id/.env`. ### Kubernetes [Section titled “Kubernetes”](#kubernetes) * [Helm chart](https://github.com/hobbit44/pocket-id-helm) by @hobbit44 * [Helm chart](https://artifacthub.io/packages/helm/anza-labs/pocket-id) by anza-labs * [Kubernetes operator](https://github.com/aclerici38/pocket-id-operator) by @aclerici38 ### Other platforms [Section titled “Other platforms”](#other-platforms) * **Unraid:** install Pocket ID from the Community Apps store. * **NixOS:** enable the module with `services.pocket-id.enable = true;`, and see its [options](https://search.nixos.org/options?channel=unstable\&query=pocket-id). * **Homebrew:** `brew install pocket-id` ## Build from source [Section titled “Build from source”](#build-from-source) Building from source needs [Go](https://go.dev/doc/install) 1.27 or newer, [Node.js](https://nodejs.org) 24 or newer with [pnpm](https://pnpm.io), and Git: ```bash git clone https://github.com/pocket-id/pocket-id cd pocket-id git checkout "$(git describe --tags "$(git rev-list --tags --max-count=1)")" # The frontend builds into the backend, which embeds it into the binary pnpm install pnpm --filter pocket-id-frontend build cd backend go build -o ../pocket-id ./cmd ``` Then create a `.env` file next to the binary and start it as in the binary steps above. # Migrate to v1 > The breaking changes in Pocket ID v1.0, from the new default port to renamed environment variables, and how to upgrade. Caution v1.0 is a major release that includes breaking changes. Please read this migration guide carefully before upgrading. We hate breaking changes as much as you do, but we decided to bundle them all into the v1.0 release to make future upgrades easier. This guide will help you understand the changes and how to migrate your existing Pocket ID installation. ## Breaking Changes [Section titled “Breaking Changes”](#breaking-changes) ### Port [Section titled “Port”](#port) * **Default Port Change**: The default port for Pocket ID has changed from `80` to `1411`. * **New Port Variable**: As Caddy has been removed and the frontend is now served directly by the backend, you no longer need to set `CADDY_PORT` or `BACKEND_PORT`. Instead, you must use the new `PORT` environment variable to specify the port on which Pocket ID listens. ### Environment Variables [Section titled “Environment Variables”](#environment-variables) | Previous Variable | New Variable | Notes | | ---------------------------- | ---------------------- | ---------------------------------------------------------------------------------------- | | `PUBLIC_APP_URL` | `APP_URL` | Variable renamed | | `PUBLIC_UI_CONFIG_DISABLED` | `UI_CONFIG_DISABLED` | Variable renamed | | `CADDY_DISABLED` | Removed | Not necessary anymore | | `CADDY_PORT` | `PORT` | Use new `PORT` variable | | `BACKEND_PORT` | `PORT` | Use new `PORT` variable | | `POSTGRES_CONNECTION_STRING` | `DB_CONNECTION_STRING` | Variable renamed. See [Database Configuration](#database-configuration) | | `SQLITE_DB_PATH` | `DB_CONNECTION_STRING` | Now uses connection string format. See [Database Configuration](#database-configuration) | | `INTERNAL_BACKEND_URL` | Removed | Not necessary anymore | ### Database Configuration [Section titled “Database Configuration”](#database-configuration) #### SQLite Configuration [Section titled “SQLite Configuration”](#sqlite-configuration) * The `SQLITE_DB_PATH` environment variable has been removed (**deprecated** since [v0.45.0](https://github.com/pocket-id/pocket-id/releases/tag/v0.45.0)) * You must now use the `DB_CONNECTION_STRING` with SQLite connection string format: * Old: `SQLITE_DB_PATH=data/pocket-id.db` * New: `DB_CONNECTION_STRING=file:data/pocket-id.db?_pragma=journal_mode(WAL)&_pragma=busy_timeout(2500)&_txlock=immediate` #### PostgreSQL Connection [Section titled “PostgreSQL Connection”](#postgresql-connection) * `POSTGRES_CONNECTION_STRING` has been removed (**deprecated** since [v0.45.0](https://github.com/pocket-id/pocket-id/releases/tag/v0.45.0)) * You must now use the `DB_CONNECTION_STRING`. The PostgreSQL connection string format remains the same: * Old: `POSTGRES_CONNECTION_STRING=postgresql://username:password@host:port/database` * New: `DB_CONNECTION_STRING=postgresql://username:password@host:port/database` ### Reverse Proxy Configuration [Section titled “Reverse Proxy Configuration”](#reverse-proxy-configuration) This releases removes the integrated Caddy server, which was used for reverse proxying and serving the frontend. **There are no actions required if you haven’t disabled Caddy with `CADDY_DISABLED=true`.** If you previously disabled Caddy, you likely had path mappings in your reverse proxy configuration. With v1.0: * Path mappings to `/api/` and `/.well-known` are no longer necessary * Your reverse proxy should now point directly to Pocket ID on port 1411 (or the port set with the `PORT` variable) ## Migration Steps [Section titled “Migration Steps”](#migration-steps) Follow the following steps to migrate from previous versions to v1.0. ### Docker [Section titled “Docker”](#docker) 1. Adapt your `docker-compose.yml` for the new version: * **Change the port**: Update the internal port to `1411` * **Change the volume path**: Update the target path for the volume to `/app/data` * **Update the healthcheck**: Change the port in the healthcheck to `1411` ```yaml services: pocket-id: image: ghcr.io/pocket-id/pocket-id:latest ports: - '1411:1411' # Change the port volumes: - ./data:/app/data # Update the volume path healthcheck: test: 'curl -f http://localhost:1411/healthz' # Update the port in the healthcheck interval: 1m30s timeout: 5s retries: 2 start_period: 10s ``` 2. Adapt the environment variables [mentioned above](#environment-variables) in your `.env` file. 3. Apply the changes by running: ```bash docker compose up -d ``` ### Standalone [Section titled “Standalone”](#standalone) While you still can build Pocket ID from source, it’s now much easier to install and upgrade Pocket ID by using the prebuilt binaries. To migrate from previous versions to v1.0 and use the prebuilt binaries, follow these steps: 1. Stop Pocket ID if it’s currently running. 2. Create a backup of the folder that contains your Pocket ID installation. ```bash cp -r /path/to/pocket-id /path/to/pocket-id-old ``` 3. Download the latest binary from the [releases page](https://github.com/pocket-id/pocket-id/releases/latest). Make sure to download the correct version for your operating system. The binary names follow this pattern: * `pocket-id--` * Example: `pocket-id-linux-amd64` You can use curl to download the binary directly. For example, for Linux on AMD64 architecture: ```bash curl -L -o pocket-id-linux-amd64 https://github.com/pocket-id/pocket-id/releases/latest/download/pocket-id-linux-amd64 ``` 4. Rename the binary and make it executable: ```bash mv pocket-id-- pocket-id chmod +x pocket-id ``` 5. If you haven’t edited the default paths where data is stored, like `UPLOAD_PATH`, `DB_CONNECTION_STRING`, `GEOLITE_DB_PATH` and `KEYS_PATH` everything is stored in the `data` directory. Because of that you have to move the `data` directory to the same folder as the new binary. Copy the `data` directory from the old Pocket ID installation to the same folder as the new binary: ```bash cp -r /path/to/pocket-id-old/data /path/to/pocket-id/data ``` 6. Create a `.env` file in the same directory as the binary. Previously you had two `.env` files, one in the `frontend` directory and one in the `backend` directory. You have to merge these two files into one `.env` file in the same directory as the binary. Make sure to also adapt the environment variables like [mentioned above](#environment-variables) Enjoy Pocket ID v1.0! We’re grateful for your ongoing support and contributions that made this milestone release possible. # Migrate to v2 > The breaking changes in Pocket ID v2.0, such as the mandatory encryption key, and how to upgrade from v1. If you’re on a version before 1.0, follow the [migration guide to v1](/docs/setup/major-releases/migrate-v1) first. If you are using Docker, you have to change the image tag in your `docker-compose.yml` from `v1` to `v2`: ```yaml services: pocket-id: image: ghcr.io/pocket-id/pocket-id:v2 # ... ``` ## Breaking Changes [Section titled “Breaking Changes”](#breaking-changes) Caution v2.0 is a major release that includes breaking changes. Please read this migration guide carefully before upgrading. ### Environment Variables [Section titled “Environment Variables”](#environment-variables) * The `ENCRYPTION_KEY` environment variable is now **mandatory**. You must set this variable to a random string of at least 16 characters. You can generate a secure random string using `openssl rand -base64 32`. * `KEYS_STORAGE` and `KEYS_PATH` have been removed. JWKs are now always stored in the database. See [JWKs on Disk](#jwks-on-disk) for more information. * `LDAP_ATTRIBUTE_ADMIN_GROUP` has been renamed to `LDAP_ADMIN_GROUP_NAME`. * `DB_PROVIDER` has been removed. We will now automatically detect the database type from the `DB_CONNECTION_STRING`. ### New Locking Mechanism [Section titled “New Locking Mechanism”](#new-locking-mechanism) v2.0 introduces a new locking mechanism which prevents multiple instances of Pocket ID from running simultaneously on the same database. This is to avoid data corruption and ensure data integrity. If you are running multiple instances of Pocket ID connected to the same database, you will need to update your deployment to ensure that only one instance is running at a time. ### JWKs on Disk [Section titled “JWKs on Disk”](#jwks-on-disk) Pocket ID used to store JWKs on the disk by default, unless `KEYS_STORAGE=database` was set. Since v2.0, JWKs are always stored in the database. **No action is required, but your users may need to re-authenticate** after the upgrade, as new keys will be generated and the old keys will no longer be available. The folder at `KEYS_PATH` (default: `data/keys`) is no longer used and can be deleted. ### Wildcards in Callback URLs [Section titled “Wildcards in Callback URLs”](#wildcards-in-callback-urls) This version makes wildcards in callback URLs more strict. If you were using wildcard callback URLs, please ensure they conform to the [new rules](/docs/advanced/callback-url-wildcards). # Reverse proxy > Serve Pocket ID over HTTPS with Caddy, nginx, Traefik or a Cloudflare Tunnel, and let it see your users' real IP addresses. Browsers only create and use passkeys in a [secure context](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts), so Pocket ID has to be served over HTTPS, except when you open it at `localhost`. Pocket ID listens on plain HTTP on port 1411, and a reverse proxy in front of it adds the HTTPS. Browsers and the apps you connect both reach Pocket ID at its public HTTPS URL, which is APP_URL. The proxy terminates TLS and forwards every path to port 1411. Point a domain such as `id.example.com` at your server, then set it as the public URL in your `.env` file: .env ```ini APP_URL=https://id.example.com ``` `APP_URL` has to be the exact address you open Pocket ID at. Passkeys are bound to its domain, and Pocket ID builds every URL it hands to your apps from it. ## Proxy configuration [Section titled “Proxy configuration”](#proxy-configuration) * Caddy Caddy fetches a certificate for the domain on its own: Caddyfile ```txt id.example.com { reverse_proxy pocket-id:1411 } ``` `pocket-id:1411` works when Caddy runs in the same Docker network as Pocket ID. For Caddy on the host, use `localhost:1411`. * nginx This server block assumes certificates from Certbot and Pocket ID’s port published on `127.0.0.1`: /etc/nginx/conf.d/pocket-id.conf ```nginx server { listen 443 ssl; server_name id.example.com; ssl_certificate /etc/letsencrypt/live/id.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/id.example.com/privkey.pem; location / { proxy_pass http://127.0.0.1:1411; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Pocket ID sends larger response headers than nginx buffers by default proxy_busy_buffers_size 512k; proxy_buffers 4 512k; proxy_buffer_size 256k; } } ``` Without the larger buffers, some pages fail with `502 Bad Gateway` and `upstream sent too big header` in nginx’s error log. * Traefik Labels on the Pocket ID service route the domain to port 1411. They assume a Traefik instance on a Docker network it shares with Pocket ID, with an entry point named `websecure` and a certificate resolver named `letsencrypt`: docker-compose.yml ```yaml services: pocket-id: # image, env_file and volumes as before labels: traefik.enable: "true" traefik.http.routers.pocket-id.rule: Host(`id.example.com`) traefik.http.routers.pocket-id.entrypoints: websecure traefik.http.routers.pocket-id.tls.certresolver: letsencrypt traefik.http.services.pocket-id.loadbalancer.server.port: "1411" ``` * Cloudflare Tunnel Add a public hostname to your tunnel, such as `id.example.com`, with the service `http://pocket-id:1411`, or `http://localhost:1411` when `cloudflared` runs on the host. Cloudflare adds the HTTPS, so nothing on your server needs a certificate. Turn off **Rocket Loader** for the domain, since it rewrites the page’s scripts and breaks Pocket ID’s [Content Security Policy](/docs/troubleshooting/common-issues#content-security-policy-errors). ## Client IP addresses [Section titled “Client IP addresses”](#client-ip-addresses) Pocket ID records the IP address and location of each sign-in in the audit log, and its rate limits count requests per IP address. Behind a proxy, every request comes from the proxy’s address, so tell Pocket ID which proxies it can trust to pass the real one on: .env ```ini # The address or network of the proxy, such as the Docker network it shares with Pocket ID TRUST_PROXY=172.18.0.0/16 ``` Behind Cloudflare, read the address from the header Cloudflare sets instead: .env ```ini TRUSTED_PLATFORM=CF-Connecting-IP ``` [Environment variables](/docs/configuration/environment-variables#reverse-proxy-settings) explains both options, and `PROXY_PROTOCOL` for load balancers that send the PROXY protocol. ## Check the setup [Section titled “Check the setup”](#check-the-setup) Open `https://id.example.com` and create your admin account on `/setup`, as [Installation](/docs/setup/installation) describes. If your browser refuses to create the passkey, the page isn’t served over HTTPS or `APP_URL` doesn’t match the address in the address bar. # Upgrading > Update Pocket ID with Docker Compose or the binary, and what to check before a major release. Pocket ID migrates its database on its own when a new version starts. Within a major version, such as 2.x, upgrades don’t need any changes to your setup. Read the [changelog](/changelog) before you upgrade, and back up the `data` folder, or your PostgreSQL database, so you can go back if something goes wrong. [Data export and import](/docs/setup/data-export-import) can create the backup. * Docker Compose The `v2` image tag follows the latest 2.x release, so pulling it gets the update: ```bash docker compose pull docker compose up -d ``` To stay on one version, use a full version tag such as `ghcr.io/pocket-id/pocket-id:v2.17.0`, and change it to upgrade. * Binary Stop Pocket ID, replace the binary with the one for your system from the [latest release](https://github.com/pocket-id/pocket-id/releases/latest), and start it again: ```bash curl -fL -o pocket-id https://github.com/pocket-id/pocket-id/releases/latest/download/pocket-id_linux_amd64 chmod +x pocket-id ./pocket-id ``` Pocket ID refuses to start an older version on a database that a newer one already migrated, unless you set `ALLOW_DOWNGRADE=true`. ## Major releases [Section titled “Major releases”](#major-releases) A major release can change settings or behavior, so it comes with a migration guide: * [Migrate to v2](/docs/setup/major-releases/migrate-v2), from 1.x * [Migrate to v1](/docs/setup/major-releases/migrate-v1), from 0.x # User management > Create users, get them to their first passkey with a login code or a signup link, and organize them in groups. Every person who signs in with Pocket ID has a user account with one or more passkeys. Only the user can add a passkey to their account, so getting someone started takes two steps: create the account, then let them in once to add their passkey. ## Create users [Section titled “Create users”](#create-users) There are four ways to get accounts into Pocket ID: * **By hand:** open **Administration → Users**, click **Add User** and fill in the username, email address and name. * **From LDAP:** Pocket ID [syncs users and groups](/docs/configuration/ldap) from your directory. * **Through signups:** users create their own account, with a [signup link](#signup-links) or freely. * **Through the API:** `POST /api/users` with an [API key](/docs/api). Turn on **Admin Privileges** for a user to give them access to the admin pages, and **Account Disabled** to block their sign-in without deleting the account. ## Add the first passkey [Section titled “Add the first passkey”](#add-the-first-passkey) Send a new user a **login code**, which signs them in once without a passkey. Pocket ID then asks them to set up a passkey, and they click **Add Passkey**. In **Administration → Users**, open the **⋯** menu of the user, choose **Login Code**, pick how long it stays valid and click **Show Code**: ![The Login Code dialog with a code, a QR code and the sign-in link](/_astro/login-code-light.Bbl96UU8_sebAl.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh)![The Login Code dialog with a code, a QR code and the sign-in link](/_astro/login-code-dark.wKx9ZJC0_1v6VUQ.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh) The user enters the code under **Alternative Sign In Methods → Login Code**, scans the QR code, or opens the link. With SMTP set up and **Email Login Code from Admin** turned on under **Application Configuration → Email**, **Send Email** mails the code instead. A login code is as good as a passkey until it expires, so send it to the person only, and keep the lifetime short. The same works for users who lost their passkeys, as [Account recovery](/docs/troubleshooting/account-recovery) describes. Passkeys can live in a password manager such as Bitwarden or 1Password, in iCloud Keychain or Google Password Manager, or on a hardware key such as a YubiKey. Users can add several, one per device or manager, under **My Account**. ## Signup links [Section titled “Signup links”](#signup-links) Signup links let people create their own account and passkey, without an admin entering their details. 1. Open **Application Configuration → User Creation** and set **Enable User Signups** to **Signup with token**. 2. In **Administration → Users**, open the **Add User** menu and choose **Create Signup Token**. 3. Choose when the token expires, how many accounts it may create and, optionally, the groups new accounts join. 4. Send the link to the people who should sign up. **View Active Signup Tokens** in the same menu lists the tokens and revokes them. **Open Signup** lets anyone who reaches Pocket ID create an account, so only use it when the instance isn’t public. Under **User Creation**, you can also add every new account to groups and give it custom claims. ## Groups [Section titled “Groups”](#groups) Groups decide who may sign in to which [OIDC client](/docs/configuration/allowed-groups), and apps receive them in the `groups` claim to assign roles. Create them under **Administration → User Groups**. A group has a **friendly name** for the admin UI and a **name** that apps see in the token, such as `Media` and `media`. Groups can carry [custom claims](/docs/guides/scopes-and-claims#custom-claims), which every member’s tokens include. # Allowed user groups > Choose which user groups may sign in to each OIDC client, and what happens to users who aren't in one of them. Each OIDC client decides who may sign in to it. Open the client under **Administration → OIDC Clients** and go to its **Access** tab: ![The Allowed User Groups card with Selected user groups chosen and the groups Family and Media ticked](/_astro/oidc-client-allowed-groups-light.CCe-H1eT_1nMVHJ.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh)![The Allowed User Groups card with Selected user groups chosen and the groups Family and Media ticked](/_astro/oidc-client-allowed-groups-dark.Ck41MM9__Z16bTiX.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh) * **Selected user groups** lets only members of the ticked groups sign in. Tick or untick groups and click **Save** in the bar at the bottom. * **All Users** lets every user sign in, and removes the client’s group selection. A client you create in the admin UI starts with **Selected user groups** and no group ticked, so nobody can sign in until you choose. Clients created through the API are open to all users unless the request restricts them. ## For users outside the groups [Section titled “For users outside the groups”](#for-users-outside-the-groups) Users who aren’t in one of the groups get “You are not allowed to access this service” instead of being sent back to the app. Apps they already signed in to lose access at their next token refresh, since Pocket ID checks the groups again every time. The groups also decide which apps a user sees on their [app dashboard](/docs/configuration/appdashboard), and, with [SCIM](/docs/configuration/scim), which users Pocket ID provisions to the app. You can also set the clients of a group from the other side, on the group’s **Allowed OIDC Clients** tab under **Administration → User Groups**. # Analytics > What the anonymous daily heartbeat of a Pocket ID instance contains, and how to turn it off. By default Pocket ID sends a heartbeat to our analytics server once every 24 hours. Seeing how many active Pocket ID instances are out there genuinely motivates our team to keep developing and maintaining the project. The instance count is also displayed on the [Pocket ID website](https://pocket-id.org). ## What We Collect [Section titled “What We Collect”](#what-we-collect) Only minimal, non-identifiable data is collected: * **Instance ID**: A random UUID (not linked to any personal information) * **Version**: Your Pocket ID version * **Heartbeat timestamps**: When your instance was first/last seen We do not log or store IP addresses, user agents, or any other potentially identifiable information. The source code of the [analytics server](https://github.com/pocket-id/analytics) is open source. ## Opting Out [Section titled “Opting Out”](#opting-out) Analytics can be disabled at any time by setting the environment variable `ANALYTICS_DISABLED` to `true`. When disabled, no data is sent to our servers. ## Public Statistics [Section titled “Public Statistics”](#public-statistics) Aggregated instance counts are displayed on our homepage. The API is publicly accessible, the docs can be found in the [analytics server repository](https://github.com/pocket-id/analytics). # App dashboard > The My Apps page lists the apps a user can sign in to, with a link to launch each one and a way to revoke their access. **My Apps** lists the OIDC clients a user may sign in to, so it doubles as a start page for everything behind Pocket ID. Users open it from the sidebar after signing in to Pocket ID. ![The My Apps page with tiles for Nextcloud, Jellyfin, Grafana, Paperless-ngx, Gitea and Home Assistant](/_astro/my-apps-light.Btz_2XTS_ZSsqkv.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh)![The My Apps page with tiles for Nextcloud, Jellyfin, Grafana, Paperless-ngx, Gitea and Home Assistant](/_astro/my-apps-dark.CXUb_2s__ZjY9xz.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh) ## Add an app to the dashboard [Section titled “Add an app to the dashboard”](#add-an-app-to-the-dashboard) A client appears on the dashboard once it has a **Client Launch URL**, which is the address **Launch** opens. Set it on the client’s **General** tab under **Administration → OIDC Clients**, together with a logo for the tile. The dashboard only shows clients that the user’s groups [allow](/docs/configuration/allowed-groups). **Show all apps** also lists the clients without a launch URL that the user signed in to before. ## Revoke access [Section titled “Revoke access”](#revoke-access) When a user signs in to a client for the first time, they agree to share their details with it. To take that back, they open the client’s **⋯** menu on the dashboard and choose **Revoke Access**, and Pocket ID asks again on their next sign-in. # Environment variables > Every environment variable Pocket ID reads, with its default, grouped by topic, plus the variables that replace the settings of the admin UI. Pocket ID reads its configuration from environment variables, and from a `.env` file in the directory it runs in. Only `ENCRYPTION_KEY` is required, and `APP_URL` has to be set for anything beyond trying Pocket ID on `localhost`. Variables that hold secrets also accept a `_FILE` variant with the path of a file that contains the value, which works with Docker secrets: `ENCRYPTION_KEY_FILE`, `DB_CONNECTION_STRING_FILE`, `STATIC_API_KEY_FILE`, `S3_SECRET_ACCESS_KEY_FILE` and `MAXMIND_LICENSE_KEY_FILE`. The file wins over the plain variable. ## Essentials [Section titled “Essentials”](#essentials) | Variable | Default | Description | | --------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `APP_URL` | `http://localhost:1411` | The address you open Pocket ID at, such as `https://id.example.com`, without a path. Passkeys are bound to its domain. | | `ENCRYPTION_KEY` | | Encrypts sensitive data such as the token signing keys, at least 16 bytes. See [Encryption keys](#encryption-keys). | | `TRUST_PROXY` | `false` | The reverse proxies to take the client IP from. See [Reverse proxy settings](#reverse-proxy-settings). | | `MAXMIND_LICENSE_KEY` | | A free [MaxMind](https://www.maxmind.com/en/geolite2/signup) key, which lets Pocket ID download the GeoLite2 database to show locations in the audit log. | | `PUID`, `PGID` | `1000` | The user and group the Docker container runs Pocket ID as, and which owns `/app/data`. They have no effect on the `-distroless` images or when the container already runs as another user. | ## Network [Section titled “Network”](#network) | Variable | Default | Description | | ------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `PORT` | `1411` | The port Pocket ID listens on. | | `HOST` | `0.0.0.0` | The address Pocket ID listens on. | | `UNIX_SOCKET` | | Listen on this Unix socket path instead of `HOST` and `PORT`. | | `UNIX_SOCKET_MODE` | | The socket’s permissions in octal, such as `0660`. | | `SYSTEMD_SOCKET` | `false` | Use the socket systemd passes in with socket activation, on Linux. Can’t be combined with `UNIX_SOCKET`. | | `TRUSTED_PLATFORM` | | The header your platform puts the client IP in, such as `CF-Connecting-IP`. See [Reverse proxy settings](#reverse-proxy-settings). | | `PROXY_PROTOCOL` | `false` | The load balancers that send the PROXY protocol. See [Reverse proxy settings](#reverse-proxy-settings). | | `INTERNAL_APP_URL` | `APP_URL` | The base URL of the token, userinfo, introspection and JWKS endpoints in the discovery document, for apps that reach Pocket ID at another address than browsers. | | `TLS_CERT_FILE`, `TLS_KEY_FILE` | | Paths of a PEM certificate and key, to serve HTTPS directly. Pocket ID reloads them when they change. | | `TLS_CERT`, `TLS_KEY` | | The PEM certificate and key as values, instead of files. They can’t be combined with the file variables. | | `LOCAL_IPV6_RANGES` | | Comma-separated IPv6 ranges, such as `2001:db8:1::/48`, that Pocket ID treats as local network, in the audit log and for [outbound requests](#outbound-requests). | ## Database and file storage [Section titled “Database and file storage”](#database-and-file-storage) | Variable | Default | Description | | ------------------------------------------ | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `DB_CONNECTION_STRING` | `data/pocket-id.db` | The SQLite database file or a PostgreSQL URL. See [Database connection string](#database-connection-string). | | `FILE_BACKEND` | `filesystem` | Where uploads such as logos and profile pictures go: `filesystem`, `database` or `s3`. | | `UPLOAD_PATH` | `data/uploads` | The uploads folder for `filesystem`, or the key prefix inside the bucket for `s3`. | | `S3_BUCKET` | | The bucket, for `FILE_BACKEND=s3`. | | `S3_REGION` | | The bucket’s region. | | `S3_ENDPOINT` | | The S3 endpoint, for storage other than AWS, such as MinIO or Cloudflare R2. | | `S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY` | | The S3 credentials. | | `S3_FORCE_PATH_STYLE` | `false` | Address the bucket in the path instead of the host name, which MinIO and some other providers need. | | `S3_DISABLE_DEFAULT_INTEGRITY_CHECKS` | `false` | Turn off the checksums newer AWS SDKs send, for providers that reject them. | | `ALLOW_DOWNGRADE` | `false` | Let an older version start on a database that a newer version already migrated, by downloading and running the newer version’s down migrations from GitHub. | ## Security [Section titled “Security”](#security) | Variable | Default | Description | | ------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `ALLOW_INSECURE_CALLBACK_URLS` | `true` | Allow `http://` callback URLs on hosts other than `localhost`. Set it to `false` unless a client needs one. | | `DISABLE_RATE_LIMITING` | `false` | Turn off the built-in rate limits. Only do this when your reverse proxy limits requests instead. | | `STATIC_API_KEY` | | An API key of at least 16 characters with admin rights, for declarative setups. It acts as a user named “Static API User”. Prefer [regular API keys](/docs/api) where you can. | | `AUDIT_LOG_RETENTION_DAYS` | `90` | How many days the audit log keeps events. | ## Outbound requests [Section titled “Outbound requests”](#outbound-requests) Some features send requests to URLs that admins or other people choose. So that such a URL can’t reach services on Pocket ID’s own network, such as a router’s admin page or a cloud metadata endpoint, each feature only connects to public addresses, plus what its variable allows. | Variable | Default | Requests | | ------------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------- | | `OUTBOUND_ALLOWED_HOSTS_SCIM` | `private,loopback` | The **SCIM Endpoint** of [SCIM](/docs/configuration/scim) clients. | | `OUTBOUND_ALLOWED_HOSTS_BACKCHANNEL_LOGOUT` | `private,loopback` | The **Back-Channel Logout URL** of OIDC clients. | | `OUTBOUND_ALLOWED_HOSTS_FEDERATED_JWKS` | `private,loopback` | The **JWKS URL** of [federated client credentials](/docs/guides/oidc-client-authentication). | | `OUTBOUND_ALLOWED_HOSTS_CLIENT_LOGO` | `none` | Logo URLs of OIDC clients. The host of `ICON_LIBRARY_URL` is always allowed. | | `OUTBOUND_ALLOWED_HOSTS_CLIENT_METADATA` | `none` | [Client ID metadata documents](/docs/guides/client-id-metadata-documents). | | `OUTBOUND_ALLOWED_HOSTS_LDAP_PICTURE` | `none` | Profile pictures that [LDAP](/docs/configuration/ldap) provides as a URL. | Each value is a comma-separated list of these entries: * `private`: `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `100.64.0.0/10` (Tailscale), `fc00::/7` and `LOCAL_IPV6_RANGES`. * `loopback`: `127.0.0.0/8` and `::1`. * An IP address or CIDR range, such as `10.0.3.7` or `172.18.0.0/16`. * A hostname, such as `scim-app`, or `*.internal` for all subdomains of `internal`, trusted whatever address it resolves to. * `none`, which allows public addresses only. ## Locations [Section titled “Locations”](#locations) Pocket ID shows where a sign-in came from in the audit log and in new-device emails. | Variable | Default | Description | | ----------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `MAXMIND_LICENSE_KEY` | | Enables downloading and updating the GeoLite2 database. | | `GEOLITE_DB_PATH` | `data/GeoLite2-City.mmdb` | Where the GeoLite2 database is stored. You can also place a database there yourself. | | `GEOLITE_DB_URL` | MaxMind’s download URL | A different download URL, where `%s` stands for the license key. A custom URL works without a key. | | `CLOUDFLARE_LOCATION_HEADERS` | `false` | Take locations from Cloudflare’s headers instead of GeoLite2. See [Cloudflare location headers](#cloudflare-location-headers). | ## Logging [Section titled “Logging”](#logging) | Variable | Default | Description | | ---------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `LOG_LEVEL` | `info` | `debug`, `info`, `warn` or `error`. | | `LOG_JSON` | `false` | Write logs as JSON. | | `LOG_QUERY_ARGS` | `false` | Include the values of database queries in debug logs and traces. They can contain personal data, so only turn this on while troubleshooting. | [Observability](#observability) covers metrics and traces. ## Other [Section titled “Other”](#other) | Variable | Default | Description | | -------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `UI_CONFIG_DISABLED` | `false` | Take the settings of **Application Configuration** from environment variables. See [Overriding the UI configuration](#overriding-the-ui-configuration). | | `ANALYTICS_DISABLED` | `false` | Turn off the daily [heartbeat](/docs/configuration/analytics) that counts running instances. | | `VERSION_CHECK_DISABLED` | `false` | Turn off the check for new releases on GitHub. | | `ICON_LIBRARY_URL` | The selfh.st icons on jsDelivr | Where the logo picker of OIDC clients searches for icons. A mirror needs the layout of the [selfh.st icons](https://github.com/selfhst/icons) repository and may be on your local network. Set it to `disabled` to turn the icon search off. | | `DISMISS_SQLITE_STORAGE_WARNING` | | Set to `i accept the risks` to hide the admin warning about a SQLite database on a network share. | | `ACTORS_PORT`, `ACTORS_HOST` | `1414`, `0.0.0.0` | The UDP port and address of Pocket ID’s internal task runtime. Only change the port if 1414 is taken. | ## Database connection string [Section titled “Database connection string”](#database-connection-string) Pocket ID supports SQLite and PostgreSQL and picks one from `DB_CONNECTION_STRING`: a URL that starts with `postgres://` or `postgresql://` is PostgreSQL, and anything else is a path to a SQLite file. ### SQLite [Section titled “SQLite”](#sqlite) SQLite needs no setup, and the default `data/pocket-id.db` is fine for most installations. Pocket ID adds the connection parameters it needs, such as write-ahead logging and a busy timeout, and you can pass a full `file:` connection string to change them. Danger Don’t store the SQLite database on a network share, such as NFS or SMB. If you have to, and know the [risks](https://www.sqlite.org/useovernet.html), add `_journal_mode=DELETE` to the connection string and keep backups. Pocket ID warns about this in the admin UI, which `DISMISS_SQLITE_STORAGE_WARNING` hides. ### PostgreSQL [Section titled “PostgreSQL”](#postgresql) Use a PostgreSQL URL: ```ini DB_CONNECTION_STRING=postgres://pocketid:password@localhost:5432/pocketid ``` Pocket ID creates its tables on the first start. Only one Pocket ID instance may use a database at a time. ## Encryption keys [Section titled “Encryption keys”](#encryption-keys) Pocket ID encrypts sensitive data, such as the keys it signs tokens with, using `ENCRYPTION_KEY`. The key must be at least 16 bytes, and a random 32-character string is a good choice: ```bash openssl rand -base64 32 ``` Set it as `ENCRYPTION_KEY`, or save it in a file and point `ENCRYPTION_KEY_FILE` at it. Pocket ID reads the file as it is, so a trailing newline becomes part of the key: write it with `printf '%s' "" > encryption_key` rather than `echo`. To change the key, re-encrypt the data with the new one, then update the variable and restart Pocket ID: ```bash # With Docker Compose docker compose exec pocket-id /app/pocket-id encryption-key-rotate --new-key # With the binary ./pocket-id encryption-key-rotate --new-key ``` ## Reverse proxy settings [Section titled “Reverse proxy settings”](#reverse-proxy-settings) Behind a [reverse proxy](/docs/setup/reverse-proxy), every request reaches Pocket ID from the proxy’s address. Pocket ID needs the client’s real IP for the audit log and its rate limits, and there are three ways to pass it on. ### `TRUST_PROXY` [Section titled “TRUST_PROXY”](#trust_proxy) A comma-separated list of the proxies’ IP addresses or CIDR ranges, such as `10.0.0.10,172.18.0.0/16`. Requests from these addresses may set the client IP in `X-Forwarded-For` or `X-Real-IP`. * `false`, the default, trusts no proxy. * `true` trusts every address, so only use it when Pocket ID can’t be reached without going through your proxy. ### `TRUSTED_PLATFORM` [Section titled “TRUSTED_PLATFORM”](#trusted_platform) The name of a header that a CDN or platform sets to the client IP, which Pocket ID then reads directly instead of `X-Forwarded-For`: * `CF-Connecting-IP` for Cloudflare * `Fly-Client-IP` for Fly.io * `X-Appengine-Remote-Addr` for Google App Engine * any header your own proxy sets Tip Prefer `TRUSTED_PLATFORM` behind a CDN that sets such a header, since it’s simpler and more reliable than listing the CDN’s addresses. ### `PROXY_PROTOCOL` [Section titled “PROXY_PROTOCOL”](#proxy_protocol) A comma-separated list of the load balancers that send the [PROXY protocol](https://www.haproxy.org/download/2.9/doc/proxy-protocol.txt) header, which carries the client address in front of the HTTP connection. Connections from the listed addresses must send the header, and connections from other addresses are rejected, except from `localhost`, so the health check keeps working. `true` expects the header from every address. It needs a TCP listener, so it can’t be combined with `UNIX_SOCKET`. ## Cloudflare location headers [Section titled “Cloudflare location headers”](#cloudflare-location-headers) With `CLOUDFLARE_LOCATION_HEADERS=true`, Pocket ID takes the country and city of sign-ins from Cloudflare’s `CF-IPCountry` and `CF-IPCity` headers instead of the GeoLite2 database, so it needs no MaxMind key. Turn on Cloudflare’s [Add visitor location headers](https://developers.cloudflare.com/rules/transform/managed-transforms/reference/#add-visitor-location-headers) managed transform, and let Pocket ID read the client IP from Cloudflare too: ```ini CLOUDFLARE_LOCATION_HEADERS=true TRUSTED_PLATFORM=CF-Connecting-IP ``` Pocket ID trusts these headers without checking where a request came from, so only use this when Pocket ID is reachable through Cloudflare alone. Locations are only known for the client of the current request, so a sign-in request from another device shows no location in this mode. ## Overriding the UI configuration [Section titled “Overriding the UI configuration”](#overriding-the-ui-configuration) The settings under **Application Configuration** are stored in the database. To manage them as environment variables instead, set `UI_CONFIG_DISABLED=true`. The admin UI then shows a notice that the settings come from the environment, and every setting you don’t set keeps its default. Booleans must be exactly `true` or `false`, and a variable set to an empty value counts as set, so leave out the ones you don’t use. `SMTP_PASSWORD` and `LDAP_BIND_PASSWORD` also accept a `_FILE` variant. ### General [Section titled “General”](#general) | Variable | Default | Description | | -------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `APP_NAME` | `Pocket ID` | The name shown in the UI and in emails, up to 30 characters. | | `SESSION_DURATION` | `60` | How many minutes a Pocket ID session lasts before users sign in again. | | `HOME_PAGE_URL` | `/settings/account` | The page users land on after signing in to Pocket ID itself. | | `ACCENT_COLOR` | `default` | The UI’s accent color, as any CSS color. | | `DISABLE_ANIMATIONS` | `false` | Turn off the UI’s animations. | | `ALLOW_OWN_ACCOUNT_EDIT` | `true` | Let users edit their own name and email address. | | `AUTO_CREATE_OIDC_CLIENT_SECRET` | `true` | Create a secret that doesn’t expire for every new confidential client. | | `CIMD_URL_ALLOWLIST` | `[]` | A JSON array of the [Client ID Metadata Document](/docs/guides/client-id-metadata-documents) URLs Pocket ID accepts. Empty turns the feature off. | ### Users and signups [Section titled “Users and signups”](#users-and-signups) | Variable | Default | Description | | ------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------- | | `REQUIRE_USER_EMAIL` | `true` | Require an email address on every account. Users without one can’t use features that send email. | | `EMAILS_VERIFIED` | `false` | Mark email addresses as verified when users sign up or change them. | | `ALLOW_USER_SIGNUPS` | `disabled` | `disabled`, `withToken` for [signup links](/docs/setup/user-management#signup-links), or `open`. | | `SIGNUP_DEFAULT_USER_GROUP_IDS` | `[]` | A JSON array of group IDs that new accounts join, such as `["a3888f2b-4c00-4b23-9c85-a3c8d685eb1f"]`. | | `SIGNUP_DEFAULT_CUSTOM_CLAIMS` | `[]` | Custom claims for new accounts, such as `[{"key":"plan","value":"free"}]`. | ### Passkeys [Section titled “Passkeys”](#passkeys) | Variable | Default | Description | | ----------------------------------- | ---------- | --------------------------------------------------------------------------------------- | | `WEBAUTHN_USER_VERIFICATION` | `required` | `required` or `preferred`, which also allows touch-only security keys. | | `WEBAUTHN_ALLOW_SYNCED_PASSKEYS` | `true` | Allow passkeys that sync between devices. | | `WEBAUTHN_AUTHENTICATOR_ATTACHMENT` | `any` | `any`, `platform` for device passkeys only, or `cross-platform` for security keys only. | [Sign-in methods](/docs/guides/sign-in-methods#passkey) explains these settings. ### Email [Section titled “Email”](#email) | Variable | Default | Description | | -------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------- | | `SMTP_HOST`, `SMTP_PORT` | | The SMTP server. | | `SMTP_FROM` | | The sender address, such as `id@example.com`. | | `SMTP_USER`, `SMTP_PASSWORD` | | The SMTP credentials. | | `SMTP_TLS` | `none` | `none`, `starttls` or `tls`. | | `SMTP_SKIP_CERT_VERIFY` | `false` | Accept self-signed certificates. | | `EMAIL_LOGIN_NOTIFICATION_ENABLED` | `false` | Email users when they sign in from a new device. | | `EMAIL_ONE_TIME_ACCESS_AS_ADMIN_ENABLED` | `false` | Let admins email a login code to a user. | | `EMAIL_ONE_TIME_ACCESS_AS_UNAUTHENTICATED_ENABLED` | `false` | Let users request a login code by email. Anyone with access to their email can then sign in as them. | | `EMAIL_API_KEY_EXPIRATION_ENABLED` | `false` | Email users before their API keys expire. | | `EMAIL_VERIFICATION_ENABLED` | `false` | Email users a link to verify their address when they sign up or change it. | ### LDAP [Section titled “LDAP”](#ldap) | Variable | Default | Description | | ----------------------------------------------------------------- | ---------------------------- | --------------------------------------------------------------------- | | `LDAP_ENABLED` | `false` | Sync users and groups from LDAP. | | `LDAP_URL` | | The server’s URL, such as `ldaps://ldap.example.com:636`. | | `LDAP_BIND_DN`, `LDAP_BIND_PASSWORD` | | The account Pocket ID searches LDAP with. | | `LDAP_BASE` | | The base DN of the search. | | `LDAP_USER_SEARCH_FILTER` | `(objectClass=person)` | Which entries are users. | | `LDAP_USER_GROUP_SEARCH_FILTER` | `(objectClass=groupOfNames)` | Which entries are groups. | | `LDAP_SKIP_CERT_VERIFY` | `false` | Accept self-signed certificates. | | `LDAP_SOFT_DELETE_USERS` | `true` | Disable users who disappear from LDAP instead of deleting them. | | `LDAP_ATTRIBUTE_USER_UNIQUE_IDENTIFIER` | | The attribute that identifies a user, whose value must never change. | | `LDAP_ATTRIBUTE_USER_USERNAME` | | The username attribute. | | `LDAP_ATTRIBUTE_USER_EMAIL` | | The email attribute. | | `LDAP_ATTRIBUTE_USER_FIRST_NAME`, `LDAP_ATTRIBUTE_USER_LAST_NAME` | | The name attributes. | | `LDAP_ATTRIBUTE_USER_DISPLAY_NAME` | `cn` | The display name attribute. | | `LDAP_ATTRIBUTE_USER_PROFILE_PICTURE` | | The profile picture attribute. | | `LDAP_ATTRIBUTE_GROUP_MEMBER` | `member` | The attribute that lists a group’s members. | | `LDAP_ATTRIBUTE_GROUP_UNIQUE_IDENTIFIER` | | The attribute that identifies a group, whose value must never change. | | `LDAP_ATTRIBUTE_GROUP_NAME` | | The group name attribute. | | `LDAP_ADMIN_GROUP_NAME` | | The group whose members become admins. | [LDAP](/docs/configuration/ldap) explains these settings. ## Observability [Section titled “Observability”](#observability) Pocket ID writes logs, and can export metrics and traces through [OpenTelemetry](https://opentelemetry.io). The standard `OTEL_*` [environment variables](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/) configure it, and every exporter is off by default. To send logs, metrics and traces to a collector: ```ini OTEL_LOGS_EXPORTER=otlp OTEL_METRICS_EXPORTER=otlp OTEL_TRACES_EXPORTER=otlp OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 ``` Traces include the database queries, without their values unless `LOG_QUERY_ARGS=true`. When traces go to an OTLP/HTTP endpoint, Pocket ID also traces page views and API calls in the browser and sends them through its own `/internal/telemetry/traces` endpoint, so the collector stays private. ### Prometheus [Section titled “Prometheus”](#prometheus) To let Prometheus scrape metrics instead, set `OTEL_METRICS_EXPORTER=prometheus`. Pocket ID then serves `/metrics` on a second port, `localhost:9464` by default, which `OTEL_EXPORTER_PROMETHEUS_HOST` and `OTEL_EXPORTER_PROMETHEUS_PORT` change. # LDAP > Sync users and groups from lldap, OpenLDAP, Active Directory or another LDAP server, set up in the admin UI or with environment variables. Pocket ID can sync users and groups from an LDAP server, such as lldap, OpenLDAP or Active Directory. The sync only reads from LDAP: users still sign in with passkeys, and Pocket ID doesn’t serve LDAP to other apps. * Pocket ID syncs a few seconds after it starts and then every hour, and **Sync now** starts one right away. * Synced users and groups are read-only in Pocket ID, so change them in LDAP. * By default, users who disappear from LDAP are disabled rather than deleted, which **Keep disabled users from LDAP** controls. ## Set up LDAP in the admin UI [Section titled “Set up LDAP in the admin UI”](#set-up-ldap-in-the-admin-ui) Open **Application Configuration → LDAP**, fill in the connection and the attribute mapping, and click **Enable**. ![The LDAP settings with the LDAP URL, bind DN, bind password, base DN and search filters](/_astro/ldap-light.BXex4LhZ_ZvpLyl.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh)![The LDAP settings with the LDAP URL, bind DN, bind password, base DN and search filters](/_astro/ldap-dark.Nk4tle_N_1KPISA.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh) | Setting | Example | Description | | ------------------------ | -------------------------------------------- | -------------------------------------------- | | **LDAP URL** | `ldaps://ldap.example.com:636` | The server’s URL with its port | | **LDAP Bind DN** | `cn=pocket-id,ou=services,dc=example,dc=com` | The account Pocket ID searches LDAP with | | **LDAP Bind Password** | | That account’s password | | **LDAP Base DN** | `dc=example,dc=com` | Where the search for users and groups starts | | **User Search Filter** | `(objectClass=person)` | Which entries are users | | **Groups Search Filter** | `(objectClass=groupOfNames)` | Which entries are groups | Under **Attribute Mapping**, map the LDAP attributes to Pocket ID’s fields: | Setting | Example | Description | | ------------------------------------- | ------------------------------- | --------------------------------------------------------------- | | **User Unique Identifier Attribute** | `entryUUID`, `objectGUID` in AD | Identifies a user across syncs, so its value must never change | | **Username Attribute** | `uid`, `sAMAccountName` in AD | The username | | **User Mail Attribute** | `mail` | The email address | | **User First Name Attribute** | `givenName` | The first name | | **User Last Name Attribute** | `sn` | The last name | | **Display Name Attribute** | `cn` | The display name, `cn` by default | | **User Profile Picture Attribute** | `jpegPhoto` | A URL, binary image or base64 image | | **Group Members Attribute** | `member` | The attribute that lists a group’s members | | **Group Unique Identifier Attribute** | `entryUUID` | Identifies a group across syncs, so its value must never change | | **Group RDN Attribute** | `cn` | The group’s name, as used in its DN | | **Admin Group Name** | `pocket-id-admins` | Members of this group become Pocket ID admins | ## Set up LDAP with environment variables [Section titled “Set up LDAP with environment variables”](#set-up-ldap-with-environment-variables) To keep the configuration in files, set `UI_CONFIG_DISABLED=true` and the `LDAP_*` variables from [Environment variables](/docs/configuration/environment-variables#overriding-the-ui-configuration), with `LDAP_ENABLED=true`. With the UI configuration disabled, every setting of **Application Configuration** comes from the environment. Since nobody has a passkey yet when you start this way, sign in as an admin from LDAP with a login code: 1. Make sure at least one user is in the group from `LDAP_ADMIN_GROUP_NAME`. 2. Start Pocket ID and wait for `LDAP sync completed` in its logs. 3. Create a login code for that user and open the link it prints: ```bash docker compose exec pocket-id /app/pocket-id one-time-access-token ``` 4. Add a passkey on your account page. # SCIM provisioning > Keep the users and groups of an app in sync with Pocket ID through SCIM, so new users exist before they sign in and removed users are gone. OIDC only tells an app who signs in, so an app learns about a user at their first sign-in and never hears when they’re deleted. With [SCIM](https://scim.cloud), Pocket ID pushes its users and groups to the app instead, so the app creates, updates and removes them as you change them in Pocket ID. The app has to offer a SCIM endpoint, and its documentation names the URL and how to get a token for it. ## Enable SCIM for a client [Section titled “Enable SCIM for a client”](#enable-scim-for-a-client) 1. Open the client under **Administration → OIDC Clients** and go to its **SCIM Provisioning** tab. 2. Enter the **SCIM Endpoint** and **SCIM Token** from the app. 3. Click **Enable**. 4. Click **Sync now** to sync right away and check the setup. ## What gets synced [Section titled “What gets synced”](#what-gets-synced) Pocket ID syncs the users who may sign in to the client and their groups. For a client restricted to [some groups](/docs/configuration/allowed-groups), that’s the members of those groups, and for a client open to all users, it’s everyone. When you change the groups, users who lose access are removed from the app at the next sync. ## When it syncs [Section titled “When it syncs”](#when-it-syncs) * Five minutes after the last change to users or groups, so a batch of changes goes out in one sync. * Every hour, even without changes. * Whenever you click **Sync now**. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) First check whether the data reached the app, by listing its users and groups through its SCIM API: ```bash curl -H "Authorization: Bearer " "/Users" curl -H "Authorization: Bearer " "/Groups" ``` If they’re there, the sync works and the problem lies in the app. If they’re missing, look for SCIM errors in Pocket ID’s logs. An error saying the connection is blocked means the endpoint resolves to an address that `OUTBOUND_ALLOWED_HOSTS_SCIM` doesn’t allow, which [Outbound requests](/docs/configuration/environment-variables#outbound-requests) explains how to change. Otherwise, [open an issue](https://github.com/pocket-id/pocket-id/issues/new/choose) if you think Pocket ID is at fault. # Page not found > The page you're looking for doesn't exist, or it moved when the docs were reorganized. Search the docs, or start from the introduction. # Callback URLs > How Pocket ID matches callback and logout URLs, and the wildcard patterns they support. Pocket ID only redirects users to the **Callback URLs** of a client after sign-in, and to its **Logout Callback URLs** after sign-out. Every client needs at least one callback URL, since Pocket ID doesn’t save the first URL an app sends anymore. * A URL has to match exactly, unless it contains a wildcard. * An `http://` URL on `localhost` or a loopback address such as `127.0.0.1`, registered without a port, matches on any port, for desktop and command-line apps that pick a free one. * `http://` URLs on other hosts work while `ALLOW_INSECURE_CALLBACK_URLS` is `true`, its default for now. * If a client has exactly one callback URL, apps may leave out `redirect_uri`. ## Wildcards [Section titled “Wildcards”](#wildcards) Both kinds of URLs support wildcard patterns, for apps whose callback URL changes, such as preview deployments. Caution If possible, prefer exact URLs instead of wildcards for better security. Two types of wildcards are supported: Single Wildcards (`*`) and Globstars (`**`). ### Single wildcard (`*`) [Section titled “Single wildcard (\*)”](#single-wildcard-) Matches **any characters inside a single segment**, such as: * one hostname label * the port value * a single path segment * a single query parameter value It will not cross segment boundaries, so it won’t consume `/`, `:`, `@`, `.`, or `[]` when those characters separate URL components. For example, `*.example.com` can match `auth.example.com`, but it cannot match `auth.eu.example.com` because that would require crossing multiple dot-separated host labels. Examples: ```plaintext https://*.example.com/oauth/callback https://app.example.com:*/oauth/callback https://user:*@example.com/oauth/callback https://example.com/oauth/*/callback https://example.com/oauth/callback?env=prod*&code=* ``` ### Globstars (`**`) [Section titled “Globstars (\*\*)”](#globstars-) Matches across multiple path segments, including `/`. **Globstars are only supported in path segments.** For example `https://example.com/**/callback` matches: ```plaintext https://example.com/callback https://example.com/oauth/callback https://example.com/api/v1/oauth/callback ``` # Custom signing keys > Rotate the key Pocket ID signs tokens with, or switch to a larger RSA key, ECDSA or EdDSA. By default, Pocket ID generates a RSA-2048 private key upon first startup, which is used to sign all tokens. You can optionally use a key with a different RSA key size (e.g. 3072 or 4096), or even a different algorithm (e.g. ECDSA with P-256, or EdDSA with Ed25519). Caution Rotating/re-generating the private key will invalidate all tokens signed by Pocket ID. You will need to restart Pocket ID for the new key to be picked up. Additionally, you may need to restart all applications that consume tokens issued by Pocket ID. Pocket ID includes a command that can be used to generate a new key, which replaces the existing one and also allows rotating the private key: ```sh pocket-id key-rotate ``` When running in a container, use a command similar to: ```sh docker compose exec pocket-id /app/pocket-id key-rotate ``` You can specify the key algorithm using the `--alg / -a` flag. Supported values include: * `RS256`: RSA (PKCS#1 v1.5) with a 2048-bit key and SHA-256 (default) * `RS384`: RSA (PKCS#1 v1.5) with a 3072-bit key and SHA-384 * `RS512`: RSA (PKCS#1 v1.5) with a 4096-bit key and SHA-512 * `ES256`: ECDSA with curve P-256 and SHA-256 * `ES384`: ECDSA with curve P-384 and SHA-384 * `ES512`: ECDSA with curve P-521 and SHA-512 * `EdDSA`: EdDSA with the curve specified with the `--crv / -c` flag; supported values: `Ed25519` For example: ```sh # Generates an ES256 token signing key pocket-id key-rotate --alg ES256 # Generates an EdDSA token signing key with Ed25519 pocket-id key-rotate --alg EdDSA --crv Ed25519 ``` Note Note that the private key is used for all OAuth2 clients. If choosing an algorithm different than RS256 (RSA), make sure that your clients support that. # Container hardening > Secure your Pocket ID deployment with distroless containers and hardening. By default, the Pocket ID container starts as the root user, which is used to set permissions on the file system before dropping its privileges and starting the main process. This is done for convenience, while still running the Pocket ID binary as non-root. If you prefer, you can run the Pocket ID container as a **non-root** user entirely and even ensure it uses a **read-only root file system**. Additionally, you can also switch to a **distroless** container, which is leaner and has a smaller potential attack surface. ## System requirements [Section titled “System requirements”](#system-requirements) Make sure that the Pocket ID data volume is writable by the chosen user. This is the volume/folder mounted in the container at `/app/data`. For example, if running the container as user `1000` and group `1000`, use a command similar to this to change the owner of the data folder: ```sh # Set the owner to user 1000 and group 1000 chown -R 1000:1000 ./data # Set permissions on all folders to 0700 find ./data -type d -exec chmod 0700 {} \; # Set permissions on all files to 0600 find ./data -type f -exec chmod 0600 {} \; ``` Note Alternatively, you can start up the regular (non-distroless) Pocket ID container with the default configuration once (where it starts as root before dropping privileges), and it will create the directories and set permissions automatically. ## Container configuration [Section titled “Container configuration”](#container-configuration) To run the container as non-root and with a read-only root file system, use one of the options below. * **Docker CLI**: Add the `--user 1000:1000 --read-only` flags to the `docker run` command. * **Docker Compose**: Set these options in the `pocket-id` service: * `read_only: true` * `user: "1000:1000"` Example: ```yaml services: pocket-id: # ... read_only: true user: '1000:1000' ``` ## Distroless container [Section titled “Distroless container”](#distroless-container) Distroless containers are based on a minimal image, which includes “just enough” to run Pocket ID. These images are leaner, resulting in faster pulls, and because they do not include a shell or other system libraries, they also have a reduced potential attack surface. To use distroless container, append `-distroless` to the container image, for example: ```plaintext ghcr.io/pocket-id/pocket-id:v2-distroless ``` You can also use a specific version (such as `v2.x.x-distroless`) or branch (`v2.x-distroless`). Note that distroless containers are non-root by default and ignore `PUID` and `PGID`. You will need to **set permissions on the mountpoints** as described in the [System requirements](#system-requirements) section. Note Distroless containers do not include a shell, so you will not be able to enter into the container (e.g. with `docker exec`) for debugging purposes. ## Docker Compose [Section titled “Docker Compose”](#docker-compose) This `docker-compose.yml` includes a full example of using Pocket ID’s distroless containers, with non-root user and a read-only root filesystem. ```yaml services: pocket-id: image: ghcr.io/pocket-id/pocket-id:v2-distroless restart: unless-stopped env_file: .env ports: - 1411:1411 volumes: - './data:/app/data' read_only: true user: '1000:1000' # Optional healthcheck healthcheck: test: ['CMD', '/app/pocket-id', 'healthcheck'] interval: 1m30s timeout: 5s retries: 2 start_period: 10s ``` # REST API > Automate Pocket ID with its REST API, authenticated with an API key, and handle its errors. Everything the admin UI does goes through the Pocket ID REST API, so you can script it, such as to create users or OIDC clients from your provisioning tools. [API endpoints](/docs/api/endpoints) lists every route with its parameters and response fields. ## Create an API key [Section titled “Create an API key”](#create-an-api-key) 1. Open **Administration → API Keys** and click **Add API Key**. 2. Enter a **Name**, an optional **Description**, and the date the key **Expires At**. 3. Click **Create API Key** and copy the key, which is only shown once. A key acts with the rights of the admin who created it. For declarative setups, such as a Kubernetes operator, `STATIC_API_KEY` sets a fixed key through an [environment variable](/docs/configuration/environment-variables#security) instead. ## Send requests [Section titled “Send requests”](#send-requests) Send the key in the `X-API-KEY` header: ```bash curl -H "X-API-KEY: " https://id.example.com/api/users ``` List endpoints take `pagination[page]` and `pagination[limit]` query parameters and answer with the items under `data` and the totals under `pagination`. ## Errors [Section titled “Errors”](#errors) Failed requests answer with an HTTP error status and a JSON body: ```json { "error": "User not found", "code": "user_not_found", "request_id": "d3fe340d-fa44-43c4-828d-893bb616ed29" } ``` `code` is stable, so check it rather than the message, and `request_id` finds the request in Pocket ID’s logs. Validation errors, with the code `validation_failed`, list each failing field under `details.fields`. ## Custom dashboards [Section titled “Custom dashboards”](#custom-dashboards) [pocket-id-portal](https://github.com/pocket-id/pocket-id-portal) is an example of a custom portal built on the API. # APIs and permissions > Let applications get access tokens for your APIs with only the permissions they need. Pocket ID can issue access tokens that an application can use to call your API. This is useful when, for example, a web app signs a user in and then needs to load data from its backend. You define: * the **API** that will receive the token; * the **permissions** that can be included in the token; and * which **OIDC clients** may request those permissions. Your API can then trust the token without creating its own login session. Note An API in this guide means a service that you built or operate. It is different from the built-in Pocket ID API and its API keys. ## A simple example [Section titled “A simple example”](#a-simple-example) Imagine you have an order management app: * the frontend is an OIDC client named `Orders App`; * the backend is an API identified by `https://api.orders.example.com`; and * the API has the permissions `read:orders` and `write:orders`. The frontend asks Pocket ID for an access token for the Orders API. The token says which API it is for and which actions are allowed. The backend checks the token before returning or changing any orders. The app asks for a token for one API and the permissions it needs. The API accepts the token only after checking its signature, its audience and the permission the request needs. ## Create an API [Section titled “Create an API”](#create-an-api) 1. Open **Administration → APIs**. 2. Select **Add API**. 3. Enter a friendly name, such as `Orders API`. 4. Enter a unique resource, such as `https://api.orders.example.com`. 5. Save the API. The resource is the permanent identifier for your API. It usually looks like a URL, but it does not need to be a page that exists. Choose it carefully because it cannot be changed later. Pocket ID removes trailing slashes, so `https://api.orders.example.com` and `https://api.orders.example.com/` identify the same resource. Issued tokens use the version without the trailing slash in their `aud` claim. ## Add permissions [Section titled “Add permissions”](#add-permissions) Open the API you created and add the actions that clients may request. Each permission has: * a **permission key** used in token requests, such as `read:orders`; * a friendly **name** shown to users, such as `Read orders`; and * an optional **description** explaining what it allows. Keep each permission focused on one action. This lets you give every client only the access it needs. ![The Orders API with the resource https://api.orders.example.com and the permissions read:orders and write:orders](/_astro/api-permissions-light.Dp2_-XYQ_Z1UOPTI.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh)![The Orders API with the resource https://api.orders.example.com and the permissions read:orders and write:orders](/_astro/api-permissions-dark.BngE9EeZ_1cEiqz.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh) ## Allow an OIDC client to use the API [Section titled “Allow an OIDC client to use the API”](#allow-an-oidc-client-to-use-the-api) 1. Open **Administration → OIDC Clients**. 2. Select the client that will call the API and go to its **Access** tab. 3. Under **API access**, click **Add API** and choose the API. 4. Select the permissions the client may request. 5. Save the changes. There are two access types: * **User-delegated access**: the client calls the API on behalf of the signed-in user. This is the usual choice for web, mobile, and desktop apps. * **Client access (M2M)**: the client calls the API as itself, without a user. This is useful for background jobs and server-to-server integrations. Public clients cannot use client access because they cannot safely keep a client secret. ## Allow metadata-document clients to use the API [Section titled “Allow metadata-document clients to use the API”](#allow-metadata-document-clients-to-use-the-api) You can grant user-delegated access to every client registered through a [Client ID Metadata Document](/docs/guides/client-id-metadata-documents): 1. Open **Administration → APIs** and select the API. 2. Under **API access**, select **Metadata document clients**. 3. Enable **Allow all metadata document clients**. 4. Select the permissions these clients may request. 5. Save the API. The grant applies to current and future metadata-document clients. It does not grant client access (M2M), because these clients are public. Manage this API-wide grant on the API rather than on an individual client. ## Request an access token for a user [Section titled “Request an access token for a user”](#request-an-access-token-for-a-user) Use your application’s normal authorization code flow. Add the API resource and the permissions you need to the authorization request: ```text resource=https://api.orders.example.com scope=openid read:orders ``` Most OIDC libraries let you add `resource` as an extra authorization parameter. Continue using the regular Pocket ID discovery URL and the authorization code flow as before. The user may be asked to approve the requested permission. After sign-in, use the returned **access token** when calling the API: ```http Authorization: Bearer ``` Do not send the ID token to the API. The ID token tells the client who signed in; the access token grants access to the API. ## Request a token without a user [Section titled “Request a token without a user”](#request-a-token-without-a-user) A confidential client can use the client credentials grant for background jobs or server-to-server calls: ```bash curl --request POST "https://id.example.com/api/oidc/token" \ --form "grant_type=client_credentials" \ --form "client_id=" \ --form "client_secret=" \ --form "resource=https://api.orders.example.com" \ --form "scope=read:orders" ``` Replace the URL and credentials with your own values. The requested permission must be enabled under **Client access (M2M)** for that OIDC client. If you do not want to store a client secret, see [OIDC Client Authentication](/docs/guides/oidc-client-authentication) for other supported authentication methods. ## Validate the token in your API [Section titled “Validate the token in your API”](#validate-the-token-in-your-api) Use a standard JWT or OAuth library in your backend. Before accepting a request, verify that: * the token’s signature is valid using the keys published by Pocket ID; * the issuer (`iss`) is your Pocket ID instance; * the audience (`aud`) contains your API’s resource; * the token has not expired; and * the token contains the permission required for the action. For example, an endpoint that returns orders should require `read:orders`, while an endpoint that changes an order should require `write:orders`. Caution Checking only that the token is signed is not enough. Always check the audience and the required permission too. # Client ID metadata documents > Let public OAuth clients provide their configuration from an HTTPS URL Client ID Metadata Documents (CIMD) let an OAuth client use an HTTPS URL as its client ID. Pocket ID fetches the JSON document at that URL and creates the client configuration when it is first used, so an administrator does not need to register every client manually. This feature follows the [OAuth Client ID Metadata Document Internet-Draft](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/). The specification is still a draft and may change. ## Enable metadata-document clients [Section titled “Enable metadata-document clients”](#enable-metadata-document-clients) Metadata-document clients are disabled by default. 1. Open **Application Configuration → OIDC**. 2. Add the exact metadata document URLs that Pocket ID should accept. 3. Save the configuration. [Wildcard URL patterns](/docs/advanced/callback-url-wildcards) are supported, but exact URLs are safer. An empty allowlist blocks all metadata-document clients. When the allowlist is not empty, Pocket ID advertises `client_id_metadata_document_supported: true` in its OpenID Connect discovery document. ## Create the metadata document [Section titled “Create the metadata document”](#create-the-metadata-document) Usually you don’t have to create a metadata document yourself. The client developer should host it at a public HTTPS URL. If you are building your own client, you can create a document like this: Host a JSON document at the HTTPS URL that the client will use as its `client_id`: ```json { "client_id": "https://app.example.com/oauth/client-metadata.json", "client_name": "Example App", "redirect_uris": ["https://app.example.com/oauth/callback"], "post_logout_redirect_uris": ["https://app.example.com/"], "token_endpoint_auth_method": "none", "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"] } ``` Serve it with a `200 OK` response and a JSON content type such as `application/json`. The `client_id` in the document must exactly match the URL used to fetch it. Pocket ID supports these metadata-document clients: * The client ID must be an HTTPS URL with a path. User information, query strings and fragments are not accepted, and private or local network destinations only when [`OUTBOUND_ALLOWED_HOSTS_CLIENT_METADATA`](/docs/configuration/environment-variables#outbound-requests) allows them. * Only public clients are supported, so `token_endpoint_auth_method` must be `none`. PKCE is enabled automatically. * Supported grant types are `authorization_code`, `urn:ietf:params:oauth:grant-type:device_code`, and `refresh_token`. At least `authorization_code` or the device code grant is required. If `grant_types` is omitted, only `authorization_code` is enabled. * The only supported response type is `code`. * Redirect and post-logout redirect URIs must be absolute URLs. Wildcards are not accepted in document-provided redirect URIs. The client sends the document URL as the `client_id` in its OAuth requests. Pocket ID downloads and caches the document, then shows the resulting client under **Administration → OIDC Clients** with the type **Metadata Document**. ## Refresh and manage a client [Section titled “Refresh and manage a client”](#refresh-and-manage-a-client) Pocket ID follows the document’s HTTP caching headers. Without an explicit cache lifetime, it refreshes the document after one hour; the maximum cache lifetime is 24 hours. Responses with `Cache-Control: no-store` cannot be used because Pocket ID must persist the resolved client. Use **Refresh** in the OIDC client list to fetch a document immediately. Fields supplied by the document are read-only in Pocket ID, while local policies such as allowed user groups, API access, and token lifetimes remain configurable. ## Grant API access [Section titled “Grant API access”](#grant-api-access) An administrator can grant an API to every current and future metadata-document client: 1. Open **Administration → APIs** and select the API. 2. Under **API access**, select **Metadata document clients**. 3. Enable access and select the permissions that these clients may request. 4. Save the API. This grants user-delegated access only. Metadata-document clients are public clients and cannot use client access (M2M). See [APIs and Permissions](/docs/guides/apis) for the complete API setup and token request flow. # OIDC client authentication > Let workloads on Kubernetes, Azure, GitLab CI or a tailnet authenticate as OIDC clients with tokens from their platform instead of a client secret. A confidential client proves who it is when it calls the token endpoint, usually with its client secret. A secret is shared between the app and Pocket ID, so it has to be stored, rotated and kept from leaking, which is where most of its risk lies. With **federated client credentials**, the client proves who it is with a token that its own platform issued instead, such as a Kubernetes service account token. Pocket ID trusts that token when its issuer, audience and subject match what you configured, so no long-lived secret exists at all: The workload proves who it is with a token its platform issued. Pocket ID checks that token against the issuer, audience and subject you configured, so no client secret is stored anywhere. The app needs to support JWT client assertions. Instead of `client_secret`, it sends these two parameters to the token endpoint: ```txt client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer client_assertion= ``` ## Configure a client [Section titled “Configure a client”](#configure-a-client) Open the client under **Administration → OIDC Clients**, go to its **Credentials** tab and click **Add Federated Client Credential**: | Field | Description | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Issuer** | The `iss` claim of the platform’s tokens. Required. | | **Subject** | The `sub` claim of the tokens. Defaults to the client ID. | | **Audience** | The `aud` claim of the tokens. Defaults to your `APP_URL`. | | **Signing keys** | Where Pocket ID gets the keys to verify the tokens: a **JWKS URL**, which defaults to `/.well-known/jwks.json`, or **Public keys** you paste in. Use HTTPS for the JWKS URL. | | **Replay Protection** | Accepts each token only once. Turn it off if the platform hands out the same token several times. | A client can have several federated credentials, such as one per environment. The platforms below each need slightly different values. ## Kubernetes service account tokens [Section titled “Kubernetes service account tokens”](#kubernetes-service-account-tokens) Using Kubernetes 1.21 or higher, you can use Projected Token Volumes to have the Kubernetes API server issue a token for the audience of your choice, and make it available to your app as projected volume. Configuration values for using Kubernetes are: * **Issuer**: Value of the Kubernetes’ API server’s issuer (this is generally passed as the value of the `--service-account-issuer` flag for `kube-apiserver`). * **Audience**: Value of the `audience` option specified when creating the Service Account for the Pod. While you can set this to any value, a good option is to use the public URL of Pocket ID. * **Subject**: The value is in the format `system:serviceaccount::`. E.g. for a *ServiceAccount* resource named `my-sa` in the namespace `myappns`, the value is `system:serviceaccount:myappns:my-sa`. * **JWKS URL** (optional): The URL where the JWKS of the Kubernetes API server can be retrieved from. The default value is `/.well-known/jwks.json`. Inside your application, you can obtain a JWT token to use as client assertion by reading the file where the projected token volume is mounted. Additional resources: * Kubernetes docs: [Configure Service Accounts for Pods](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) * Kubernetes docs: [Projected Volumes for `serviceAccountToken`](https://kubernetes.io/docs/concepts/storage/projected-volumes/#serviceaccounttoken) ## Microsoft Azure [Section titled “Microsoft Azure”](#microsoft-azure) On Microsoft Azure, you can use Microsoft Entra Workload ID (e.g. Managed Identity or Workload Identity) to federate with Pocket ID. Set up steps for Azure: 1. Assign an identity to your application, such as a System-assigned or User-assigned Identity. [Instructions](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) are specific to each service being used. * For workloads running on Azure Kubernetes Service, you may want to use [Workload Identity](https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview) 2. Create an application in Microsoft Entra ID ([docs](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app)) * Take note of the client ID of this app, which will be a UUID * Configure the Entra ID app with Federated credentials for the Managed Identity created for your resource ([docs](https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation)) Configuration values for Federated Client Credentials in Pocket ID: * **Issuer**: `https://sts.windows.net//` where `` is the UUID of your Microsoft Entra ID tenant * **Audience**: The client ID of the Entra ID application created above * **Subject**: The object ID of the managed identity (note: this is the *object* (or *principal*) ID, not a client ID) * **JWKS URL**: Constant value `https://login.microsoftonline.com/common/discovery/keys` Inside your application, you can [obtain a token](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token) from the Managed Identity by: * Recommended: using one of the Azure SDKs to get a token from Managed Identity, with the requested *resource* as the client ID of the Entra ID application. SDKs work on all Azure services automatically. * Manually invoking the endpoint metadata service. The endpoint can be different depending on the Azure service; in the case of an Azure Virtual Machine, the URL is `http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=` (where `` is the client ID of the Entra ID application); make sure to also set the HTTP header `Metadata:true` in the request. ## Tailscale with tsiam [Section titled “Tailscale with tsiam”](#tailscale-with-tsiam) If your application is running on a node that is joined to a Tailscale network (“tailnet”), you can use the third-party [tsiam](https://github.com/ItalyPaleAle/tsiam) application to provide workload identity. When requesting a workload identity token from tsiam, it’s recommended to set as resource the endpoint of Pocket ID, for example `https://pocketid.example.com` Configuration values for Federated Client Credentials in Pocket ID: * **Issuer**: The URL of your tsiam instance inside the tailnet, for example `https://tsiam.tail.ts.net` * **Audience**: The value of the resource used when requesting a token from tsiam; recommended to use the endpoint of Pocket ID (e.g. `https://pocketid.example.com`) * **Subject**: The full name of the node in the tailnet, e.g. `.tail.ts.net` * **JWKS URL**: Leave empty to use the default value ## GitLab CI [Section titled “GitLab CI”](#gitlab-ci) When running jobs in GitLab Pipelines, your job can authenticate as an OIDC client with Pocket ID using [GitLab ID tokens](https://docs.gitlab.com/ci/secrets/id_token_authentication/). Configuration values for Federated Client Credentials in Pocket ID: * **Issuer**: `https://gitlab.com` (or your self-hosted GitLab domain) * **Audience**: `https://pocketid.example.com` - recommended to use the Pocket ID endpoint as the audience. * **Subject**: `project_path:my-group/my-project:ref_type:branch:ref:main` - replace `my-group/my-project` with the project you will be running the pipeline on. If working on a branch, change `main` to your branch name. Currently, wildcards are not supported, so if you need to authenticate from pipelines running on different branches, you will need to create a Federated Client Credential for each branch. * **JWKS URL**: `https://gitlab.com/oauth/discovery/keys` - if self-hosting, replace `gitlab.com`. Here’s an example GitLab job that authenticates as an OIDC client: .gitlab-ci.yml ```yaml example-job: image: alpine:3.23.3 id_tokens: GL_PIPELINE_TOKEN: aud: "$POCKET_ID_URL" # must match the `Audience` configured in Pocket ID. script: - apk update - apk add --no-cache curl jq - responsefile=$(mktemp) - | curl -SsfX POST --url "$POCKET_ID_URL/api/oidc/token" \ -F "grant_type=client_credentials" \ -F "client_id=$POCKET_ID_CLIENT_ID" \ -F "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \ -F "client_assertion=$GL_PIPELINE_TOKEN" \ -o "$responsefile" - access_token=$(jq '.access_token' -r < "$responsefile") - echo "Successfully obtained token with subject: client-$POCKET_ID_CLIENT_ID" ``` The only variables you need to define are: * `POCKET_ID_URL`: The base URL of your pocket ID instance, such as `https://pocketid.example.com`. In the job above this URL is also used as the Audience of the Federated Client Credential. * `POCKET_ID_CLIENT_ID`: the client ID of the OIDC Client configured in Pocket ID. In the job above the `client_credentials` grant type is used, which means that the final token will have a subject of the form `client-[client_id]` (as opposed to a uuid identifying a user). # Authentication proxies > Put apps without OIDC support behind Pocket ID with Tinyauth, caddy-security, OAuth2 Proxy or Traefik forward auth. Pocket ID only provides OpenID Connect, so it can’t protect an app that has no OIDC support by itself. An authentication proxy closes that gap: it sits in front of the app as the OIDC client, and only lets requests through once the visitor signed in with Pocket ID. The authentication proxy is the OIDC client. It sends visitors without a session to Pocket ID, and only forwards requests to the app once they signed in. Most proxies also forward the user’s name, email address and groups to the app in HTTP headers, which some apps use to sign the user in. Use [allowed user groups](/docs/configuration/allowed-groups) on the proxy’s client to decide who gets through. The proxies below work with Pocket ID, and most other reverse proxies offer something similar in their documentation. ## Tinyauth [Section titled “Tinyauth”](#tinyauth) [Tinyauth](https://tinyauth.app/) is a lightweight authentication middleware designed specifically for homelabs. Currently it integrates with Traefik, Caddy and Nginx Proxy Manager. Refer to the official [Tinyauth Pocket ID documentation](https://tinyauth.app/docs/guides/pocket-id) for detailed instructions on how to set up Tinyauth with Pocket ID. ## Caddy [Section titled “Caddy”](#caddy) [caddy-security](https://github.com/greenpau/caddy-security) adds OIDC sign-in to Caddy. 1. Create an OIDC client in Pocket ID with the callback URL `https:///caddy-security/oauth2/generic/authorization-code-callback`, and note its client ID and secret. 2. Add the plugin to Caddy: ```bash caddy add-package github.com/greenpau/caddy-security ``` 3. Configure the identity provider, the portal and a policy, and protect your service with them: Caddyfile ```txt { # Port to listen on http_port 443 # Configure caddy-security. order authenticate before respond security { oauth identity provider generic { delay_start 3 realm generic driver generic client_id client-id-from-pocket-id # Replace with your own client ID client_secret client-secret-from-pocket-id # Replace with your own client secret scopes openid email profile base_auth_url https:// #Replace metadata_url https:///.well-known/openid-configuration #Replace } authentication portal myportal { crypto default token lifetime 3600 # Seconds until you have to re-authenticate enable identity provider generic cookie insecure off # Set to "on" if you're not using HTTPS # cookie domain service.example.com - If using multiple clients/portals you have to set the cookie domain for each one so they do not conflict when trying to refresh the session. trust login redirect uri domain exact service.example.com path prefix / transform user { match realm generic action add role user } } authorization policy mypolicy { set auth url /caddy-security/oauth2/generic allow roles user inject headers with claims } } } https:// { @auth { path /caddy-security/* } route @auth { authenticate with myportal } route /* { authorize with mypolicy reverse_proxy http://: # Replace with your own service } } ``` 4. Start Caddy: ```bash caddy run --config Caddyfile ``` The [caddy-security documentation](https://docs.authcrunch.com/docs/intro) covers the other options. ## OAuth2 Proxy [Section titled “OAuth2 Proxy”](#oauth2-proxy) [OAuth2 Proxy](https://oauth2-proxy.github.io/oauth2-proxy/) runs next to the app and forwards signed-in requests to it, here for [Uptime Kuma](https://github.com/louislam/uptime-kuma). 1. Create an OIDC client in Pocket ID with the callback URL `https:///oauth2/callback`, and note its client ID and secret. 2. Add OAuth2 Proxy to the app’s `docker-compose.yml`: ```yaml # Example with Uptime Kuma # uptime-kuma: # image: louislam/uptime-kuma oauth2-proxy: image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0 command: --config /oauth2-proxy.cfg volumes: - './oauth2-proxy.cfg:/oauth2-proxy.cfg' ports: - 4180:4180 ``` 3. Create `oauth2-proxy.cfg` next to it: oauth2-proxy.cfg ```ini # Replace with your own credentials client_id="client-id-from-pocket-id" client_secret="client-secret-from-pocket-id" oidc_issuer_url="https://" # Replace with a secure random string cookie_secret="random-string" # Upstream servers (e.g http://uptime-kuma:3001) upstreams="http://:" # Additional Configuration provider="oidc" scope = "openid email profile groups" # If you are using a reverse proxy in front of OAuth2 Proxy reverse_proxy = true # Email domains allowed for authentication email_domains = ["*"] # If you are using HTTPS cookie_secure="true" # With HTTPS use "__Host-" or "__Secure-" prefix, otherwise leave blank cookie_name="__Host-oauth2-proxy" # Listen on all interfaces http_address="0.0.0.0:4180" ``` 4. Start the services: ```bash docker compose up -d ``` Visitors now reach the app through OAuth2 Proxy on port 4180, which your reverse proxy should forward the app’s domain to. Without Docker the setup is the same, and the [OAuth2 Proxy documentation](https://oauth2-proxy.github.io/oauth2-proxy/configuration/overview) covers the other options. ## Traefik [Section titled “Traefik”](#traefik) [Traefik](https://traefik.io/traefik/) does not have built-in support for OpenID Connect, but can be integrated in two ways. Note: Traefik Enterprise has an [OIDC middleware](https://doc.traefik.io/traefik-enterprise/middlewares/oidc/) out of the box if you happen to be using that. ### Using forward auth [Section titled “Using forward auth”](#using-forward-auth) Using forward auth, for example with [traefik-forward-auth v4](https://github.com/ItalyPaleAle/traefik-forward-auth), involves running a separate service alongside Traefik (as a “sidecar” configured in the Docker Compose file or Pod spec). Traefik invokes the forward auth service behind the scenes to authorize requests, redirecting the user to it if it needs to authenticate. traefik-forward-auth v4 includes support for Pocket ID and other authentication providers. See the documentation for [configuring traefik-forward-auth](https://traefik-forward-auth.italypaleale.me/docs/quickstart/) and [integrating it](https://traefik-forward-auth.italypaleale.me/providers/pocket-id/) with Pocket ID. ### Using a Traefik plugin [Section titled “Using a Traefik plugin”](#using-a-traefik-plugin) Traefik includes experimental support for plugins that run in-process. [Traefik OpenID Connect Middleware](https://plugins.traefik.io/plugins/66b63d12d29fd1c421b503f5/oidc-authentication) works with Pocket ID. See the [Pocket ID configuration docs](https://traefik-oidc-auth.sevensolutions.cc/docs/identity-providers/pocket-id) for Pocket ID specific instructions, and [Getting Started](https://traefik-oidc-auth.sevensolutions.cc/docs/getting-started) for more details on how to apply the configuration to a specific endpoint. # Scopes and claims > The scopes Pocket ID supports, the claims each one adds to the ID token and userinfo, custom claims, and how long tokens last. An app chooses what it learns about a user through the scopes it requests. Pocket ID puts the matching claims into the ID token and returns the same claims from the userinfo endpoint. ## Scopes [Section titled “Scopes”](#scopes) | Scope | Claims | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `openid` | `sub`, the user’s ID, which never changes. Every sign-in needs this scope. | | `profile` | `name`, `given_name`, `family_name`, `preferred_username`, `display_name`, `picture`, and the user’s [custom claims](#custom-claims) | | `email` | `email` and `email_verified`, when the user has an email address | | `groups` | `groups`, the names of the user’s groups as an array | | `offline_access` | No claims, since Pocket ID issues refresh tokens without it | `preferred_username` is the username, and `name` is the first and last name, or the display name or username when the user has no name set. `picture` is a URL of the user’s profile picture. Pocket ID ignores scopes it doesn’t know, except the permissions of [your APIs](/docs/guides/apis). Groups appear by their **name**, such as `media`, not by the friendly name shown in the admin UI. Apps that map groups to roles, such as Grafana or Jellyfin, need these names. ## Custom claims [Section titled “Custom claims”](#custom-claims) Custom claims add your own values to the tokens, such as a role or a quota for one app. Set them on a user or a group under **Administration → Users** or **User Groups**, on the **Custom Claims** tab. * They’re released with the `profile` scope, in the ID token and the userinfo response, but not in the access token. * A value that is valid JSON, such as `["admin"]` or `42`, is added as JSON, and anything else as a string. * A user’s own claim wins over a group’s claim with the same name. If several of the user’s groups set the same claim, which one wins isn’t defined, so give every group its own names. * Standard claim names such as `email`, `groups`, `name` or `sub` are reserved and can’t be used. To check what an app will receive, open the client and click **OIDC Data Preview**, which shows the ID token, the access token and the userinfo response for any user. ## Tokens [Section titled “Tokens”](#tokens) | Token | Format | Lifetime | | ------------------ | --------------------------------------------------------------- | ---------------------------------------------- | | ID token | Signed JWT | 1 hour | | Access token | Signed JWT ([RFC 9068](https://www.rfc-editor.org/rfc/rfc9068)) | 60 minutes, configurable per client | | Refresh token | Opaque | 30 days of inactivity, configurable per client | | Authorization code | Opaque | 15 minutes | Change a client’s lifetimes under **Token lifetimes** on its **General** tab. A refresh token’s lifetime restarts whenever the app uses it, so an app that refreshes regularly stays signed in. Pocket ID checks at every refresh that the user still exists, isn’t disabled and is still in one of the client’s allowed groups, so removing someone from a group ends their access at the app’s next refresh. The access token’s audience (`aud`) is the client ID, or the API’s resource when the app asked for one of [your APIs](/docs/guides/apis). Tokens are signed with RS256 by default, and [Custom signing keys](/docs/advanced/custom-keys) switches to another algorithm. # Sign-in methods > How users sign in with a passkey, from another device, with a login code or by email, and the passkey policies admins can set. Users sign in to Pocket ID with a passkey. When they don’t have one at hand, **Alternative Sign In Methods** on the sign-in page offers the other ways: ![The Alternative Sign In page with the options Sign in with another device and Login Code](/_astro/sign-in-alternatives-light.CUsWQQB9_Z1WUUsi.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh)![The Alternative Sign In page with the options Sign in with another device and Login Code](/_astro/sign-in-alternatives-dark.Drwjsx9x_1iqqLP.webp?dpl=dpl_DKTcocWPMX5PTAwfpzjuD1bT5ZSh) ## Passkey [Section titled “Passkey”](#passkey) A passkey is a key pair: the private half stays on the user’s device, password manager or security key, and Pocket ID only stores the public half. The user unlocks it with a fingerprint, face scan or PIN, and it only works on the domain it was created for, which makes phishing it close to impossible. Admins decide which passkeys are allowed under **Application Configuration → Passkeys**: | Setting | Effect | | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | | **User verification** | **Required** makes every sign-in ask for a fingerprint, face scan or PIN, **Preferred** also allows touch-only security keys | | **Allow synced passkeys** | Allows passkeys that sync between devices, such as those in iCloud Keychain or a password manager | | **Allowed authenticator type** | **Any passkey**, **Device passkeys only** or **External security keys only**, such as USB or NFC keys | User verification applies to every sign-in, while the other two settings only apply to passkeys added from then on. ## Sign in with another device [Section titled “Sign in with another device”](#sign-in-with-another-device) Users can sign in on a device without their passkey, such as a borrowed laptop or a TV, by approving the sign-in on their phone: The new device shows a QR code and waits. Once you approve the request with your passkey on your phone, the new device is signed in. The request expires after 5 minutes. 1. On the new device, choose **Alternative Sign In Methods → Sign in with another device**. 2. Scan the QR code with the phone that has the passkey, or open the shown address there and enter the code. 3. Sign in on the phone with the passkey if it asks, check the device and location it shows, and click **Approve**. Only approve requests you started yourself, since approving one signs that device in to your account. ## Login code [Section titled “Login code”](#login-code) An admin can create a login code that signs a user in once, to add a first passkey or to get back in after losing all of them. [User management](/docs/setup/user-management#add-the-first-passkey) shows how to create one in the admin UI, and [Account recovery](/docs/troubleshooting/account-recovery) how to create one from the command line. The user enters it under **Alternative Sign In Methods → Login Code**, or opens the link that comes with it. ## Login code by email [Section titled “Login code by email”](#login-code-by-email) Weakens your security With this method, anyone who can read a user’s email can sign in as them, so their email account becomes as valuable as their passkey. With SMTP set up under **Application Configuration → Email**, turn on **Email Login Code Requested by User**. **Alternative Sign In Methods** then also offers **Email Login**, where users request a login code for their email address. # Contributing > How to report bugs, propose features and set up a development environment for Pocket ID. Contributions are welcome, from bug reports and ideas to translations and code. ## Report a bug or suggest a feature [Section titled “Report a bug or suggest a feature”](#report-a-bug-or-suggest-a-feature) Open an [issue on GitHub](https://github.com/pocket-id/pocket-id/issues/new/choose), or ask on [Discord](https://discord.gg/8wudU9KaxM) first if you’re not sure it’s a bug. Before you start working on a feature, open an issue or comment on an existing one, so the implementation can be agreed on before you spend time on it. ## Contribute code [Section titled “Contribute code”](#contribute-code) [The contribution guidelines](https://github.com/pocket-id/.github/blob/main/CONTRIBUTING.md) describe the rules for pull requests, including how AI tools may be used. See [Development](/docs/helping-out/development) for the development setup, formatting, and tests. To improve these docs, see [Documentation](/docs/helping-out/documentation), and to translate Pocket ID, see [Translating](/docs/helping-out/translating). # Development > Set up the Pocket ID development environment, format the code, and run tests. Follow the [shared contribution guidelines](https://github.com/pocket-id/.github/blob/main/CONTRIBUTING.md) before submitting a pull request. ## Formatting [Section titled “Formatting”](#formatting) Run `pnpm format` from the repository root before submitting a pull request. ## Development Environment [Section titled “Development Environment”](#development-environment) Pocket ID consists of a frontend and backend. In production the frontend gets statically served by the backend, but in development they run as separate processes to enable hot reloading. There are two ways to get the development environment setup: ### 1. Install required tools [Section titled “1. Install required tools”](#1-install-required-tools) #### With Dev Containers [Section titled “With Dev Containers”](#with-dev-containers) If you use [Dev Containers](https://code.visualstudio.com/docs/remote/containers) in VS Code, you don’t need to install anything manually, just follow the steps below. 1. Make sure you have [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension installed 2. Clone and open the repo in VS Code 3. VS Code will detect .devcontainer and will prompt you to open the folder in devcontainer 4. If the auto prompt does not work, hit `F1` and select `Dev Containers: Open Folder in Container.`, then select the pocket-id repo root folder and it’ll open in container. #### Without Dev Containers [Section titled “Without Dev Containers”](#without-dev-containers) If you don’t use Dev Containers, you need to install the following tools manually: * [Node.js](https://nodejs.org/en/download/) >= 24 * [Go](https://golang.org/doc/install) >= 1.27 * [Git](https://git-scm.com/downloads) ### 2. Setup [Section titled “2. Setup”](#2-setup) #### Backend [Section titled “Backend”](#backend) The backend is built with [Gin](https://gin-gonic.com) and written in Go. To set it up, follow these steps: 1. Open the `backend` folder 2. Copy the `.env.development-example` file to `.env` and edit the variables as needed 3. Start the backend with `go run -tags exclude_frontend ./cmd` #### Frontend [Section titled “Frontend”](#frontend) The frontend is built with [SvelteKit](https://kit.svelte.dev) and written in TypeScript. To set it up, follow these steps: 1. Open the `pocket-id` project folder 2. Copy the `frontend/.env.development-example` file to `frontend/.env` and edit the variables as needed 3. Install the dependencies with `pnpm install` 4. Start the frontend with `pnpm dev` You’re all set! The application is now listening on `localhost:3000`. The backend gets proxied trough the frontend in development mode. ## Testing [Section titled “Testing”](#testing) If you are contributing to a new feature please ensure that you add tests for it. ### End-to-end tests [Section titled “End-to-end tests”](#end-to-end-tests) We are using [Playwright](https://playwright.dev) for end-to-end testing. The tests are located in the `tests` folder at the root of the project. The tests can be run like this: 1. Install the dependencies from the root of the project `pnpm install` 2. Visit the setup folder by running `cd tests/setup` 3. Start the test environment by running `docker compose up -d --build` 4. Go back to the test folder by running `cd ..` 5. Run the tests with `pnpm dlx playwright test` or from the root project folder `pnpm test` If you make any changes to the application, you have to rebuild the test environment by running `docker compose up -d --build` again. ### Unit tests [Section titled “Unit tests”](#unit-tests) In the backend we are using unit tests with the built-in Go testing framework. The tests are located in the same folder as the code they are testing and have the `_test.go` suffix. To run the tests, simply run `go test -tags=exclude_frontend,unit ./...` from the root of the `backend` folder. # Documentation > Run the Pocket ID website locally, write or edit a docs page, and add a setup guide for an app. The website is built with [Astro](https://astro.build) and [Starlight](https://starlight.astro.build), and lives in the [pocket-id/website](https://github.com/pocket-id/website) repository. ## Run it locally [Section titled “Run it locally”](#run-it-locally) ```bash pnpm install pnpm dev ``` The dev server runs at `http://localhost:4321` and reloads when you save a page. The API endpoints page is generated from the backend’s code with [swag](https://github.com/swaggo/swag), and a workflow keeps the generated spec in the repository up to date. To see endpoint changes before that, run `pnpm openapi` with Go installed and a checkout of [pocket-id/pocket-id](https://github.com/pocket-id/pocket-id) next to the website repository, or point `POCKET_ID_DIR` at a checkout somewhere else. ## Add or edit a page [Section titled “Add or edit a page”](#add-or-edit-a-page) Pages are Markdown files in `src/content/docs/docs/`, and the path of a file is its address: `src/content/docs/docs/setup/installation.md` is served at `/docs/setup/installation`. Each page starts with a title and a description: ```md --- title: My feature description: One sentence about what the page helps with, shown in search results. --- ``` Add a new page to the `sidebar` in `astro.config.mjs`, except client examples, which the sidebar lists automatically. Use `.mdx` instead of `.md` when a page needs components, such as [tabs](https://starlight.astro.build/components/tabs/) or [steps](https://starlight.astro.build/components/steps/). ## Add a client example [Section titled “Add a client example”](#add-a-client-example) A client example is a file in `src/content/docs/docs/client-examples/`, named like the app’s icon in [selfh.st icons](https://selfh.st/icons), such as `immich.md`. It appears on the overview with that icon automatically. Describe the OIDC client in the frontmatter, and the `::create-client` line turns it into the steps for Pocket ID, so you only write how to configure the app: ```md --- title: Immich description: Sign in to the Immich photo library with Pocket ID. client: callbackUrls: - https://immich.example.com/auth/login --- ::create-client ## Configure Immich 1. In Immich, open **Administration → Settings → Authentication Settings → OAuth**. ``` | Field | What it does | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `callbackUrls` | The app’s callback URLs, required | | `logoutCallbackUrls` | Where the app sends users after signing out | | `public` | `true` for apps that can’t keep a client secret, such as single-page and mobile apps | | `pkce` | `true` to turn on PKCE for a confidential client | | `customClientId` | A fixed client ID the app expects | | `launchUrl` | The address the app opens from **My Apps** | | `allowedGroups` | The groups the guide created for the app, which then may sign in instead of groups the reader chooses | | `values` | What the app asks for, from `clientId`, `clientSecret`, `discoveryUrl`, `issuerUrl`, `authorizationUrl`, `tokenUrl`, `userinfoUrl`, `logoutUrl` and `certificateUrl`, the client ID, secret and discovery URL if left out | Use `https://id.example.com` for Pocket ID and `https://.example.com` for the app, and the app’s exact field names in bold. ## Callouts [Section titled “Callouts”](#callouts) ```md :::note Something worth knowing. ::: :::caution Something that can go wrong. ::: ``` The types are `note`, `tip`, `caution` and `danger`. ## Images [Section titled “Images”](#images) Put images under `public/img/` and reference them with an absolute path and alt text: ```md ![The OIDC client form](/img/example/client-form.png) ``` ### Screenshots of Pocket ID [Section titled “Screenshots of Pocket ID”](#screenshots-of-pocket-id) Screenshots of Pocket ID itself come in a light and a dark version, and the `Screenshot` component shows the one matching the reader’s theme: ```mdx import Screenshot from '../../../../components/Screenshot.astro'; ``` `pnpm screenshots` recreates all of them in `src/assets/screens/` from a fresh Pocket ID container with demo data, so they stay consistent when the UI changes. It needs Docker and Playwright’s Chromium, which `pnpm exec playwright install chromium` installs. ### Diagrams [Section titled “Diagrams”](#diagrams) Diagrams are inline SVG components in `src/components/diagrams/`, drawn with the shared classes in `classes.ts` so they follow the theme. Request flows only need a list of parties and messages for the `Sequence` component, as `SignInFlow.astro` shows. ## Submit your changes [Section titled “Submit your changes”](#submit-your-changes) Open a pull request with a title that follows [Conventional Commits](https://www.conventionalcommits.org), such as `docs: add Vikunja example`. Each pull request gets a preview deployment. # Sponsors > The companies and people who sponsor Pocket ID, and how to support its maintainers on GitHub Sponsors. ## GitHub Sponsors [Section titled “GitHub Sponsors”](#github-sponsors) Thanks to everyone who supports Pocket ID by becoming a sponsor! You truly don’t know how much that means to us and how much it helps support the behind the scenes functions for the project. If you would like to sponsor us, you can do so on GitHub: * ![](https://avatars.githubusercontent.com/u/58886915?v=4)Elias SchneiderCreator and maintainer[Sponsor](https://github.com/sponsors/stonith404) * ![](https://avatars.githubusercontent.com/u/25576967?v=4)Kyle MendellMaintainer[Sponsor](https://github.com/sponsors/kmendell) ## Tools [Section titled “Tools”](#tools) Thanks to these companies for giving the project their tools for free. * [![JetBrains](/img/sponsors/jetbrains-light.svg)![JetBrains](/img/sponsors/jetbrains-dark.svg)Free All Products Pack subscriptions for open source maintainers.](https://jb.gg/OpenSource) * [![Depot](/img/sponsors/depot-light.svg)![Depot](/img/sponsors/depot-dark.svg)Fast CI/CD pipelines, free for open source projects.](https://depot.dev) * [![Snyk](/img/sponsors/snyk-light.svg)![Snyk](/img/sponsors/snyk-dark.svg)Free licenses that help keep Pocket ID secure.](https://snyk.io) * [![Vercel](/img/sponsors/vercel-light.svg)![Vercel](/img/sponsors/vercel-dark.svg)Free hosting for this website trough the Vercel OSS program.](https://vercel.com) * [![OrbStack](/img/sponsors/orbstack.png)![OrbStack](/img/sponsors/orbstack.png)OrbStackFree OrbStack Pro license for lightweight container development on macOS.](https://orbstack.dev) * [![OpenAI](/img/sponsors/openai-light.svg)![OpenAI](/img/sponsors/openai-dark.svg)Free Codex access through the Codex for Open Source program.](https://developers.openai.com/community/codex-for-oss) * [![Anthropic](/img/sponsors/anthropic-light.svg)![Anthropic](/img/sponsors/anthropic-dark.svg)Free Claude Max access through the Claude for Open Source program.](https://claude.com/contact-sales/claude-for-oss) # Translating > Help translate the Pocket ID interface into your language on Crowdin, or add a language that is missing. Help us make Pocket ID accessible in your language by contributing translations. ## Guidelines [Section titled “Guidelines”](#guidelines) * Use informal language for translations ## Get started [Section titled “Get started”](#get-started) 1. Visit our [Crowdin project page](https://crowdin.com/project/pocket-id). 2. Choose the language you wish to translate into. 3. Open the `en.json` source file. 4. Now you can start translating the strings. ## Add a new language [Section titled “Add a new language”](#add-a-new-language) Is your language missing from Crowdin? You can [request its addition](https://github.com/pocket-id/pocket-id/issues/new?assignees=\&labels=language-request\&projects=\&template=language-request.yml\&title=%F0%9F%8C%90+Language+request%3A+%3Clanguage+name+in+english%3E). ## Get help [Section titled “Get help”](#get-help) Encountering issues while translating? Join the [Localization discussion](https://github.com/pocket-id/pocket-id/discussions/370) to seek help and share experiences. # Account recovery > Let a user back in who lost their passkeys, or yourself when you lost the last admin passkey, with a one-time login code. A user who lost all their passkeys signs in once with a **login code** and adds a new passkey. ## A user lost their passkeys [Section titled “A user lost their passkeys”](#a-user-lost-their-passkeys) An admin creates the login code in **Administration → Users**, from the **⋯** menu of the user with **Login Code**, as [User management](/docs/setup/user-management#add-the-first-passkey) shows. The user opens the link or enters the code under **Alternative Sign In Methods → Login Code**, then adds a passkey on their account page. If they still have a passkey on another device, they don’t need a code: [Sign in with another device](/docs/guides/sign-in-methods#sign-in-with-another-device) gets them in with it. ## You lost the admin passkey [Section titled “You lost the admin passkey”](#you-lost-the-admin-passkey) Without access to the admin UI, create the login code on the server instead: ```bash # With Docker Compose docker compose exec pocket-id /app/pocket-id one-time-access-token # With the binary ./pocket-id one-time-access-token ``` The command prints a link that signs the user in once within the next hour: ```txt A one-time access token valid for 1 hour has been created for "taylor". Use the following URL to sign in once: https://id.example.com/lc/YCvmQgrJbX0zEZbh ``` Anyone with the link can sign in as that user, so only send it to the person it’s for. # Common issues > Fixes for the problems people run into most often, from passkeys that won't register to callback URL and group errors. ## Passkeys don’t work [Section titled “Passkeys don’t work”](#passkeys-dont-work) The browser refuses to create or use a passkey, or shows “Passkeys are not configured correctly for this domain”. * Pocket ID has to be served over HTTPS, except on `localhost`, as [Reverse proxy](/docs/setup/reverse-proxy) shows. * `APP_URL` has to match the address in the browser exactly, such as `APP_URL=https://id.example.com`. Passkeys are bound to that domain, so a passkey created for one domain doesn’t work on another, and changing the domain later means adding new passkeys. A passkey prompt that fails with “Your passkey couldn’t verify you” comes from a security key without a PIN, while **User verification** is set to **Required**. Set a FIDO2 PIN on the key, or choose **Preferred** under [Application Configuration → Passkeys](/docs/guides/sign-in-methods#passkey). ## The setup page is gone [Section titled “The setup page is gone”](#the-setup-page-is-gone) `/setup` only works until the first account exists. If you created an account but never added a passkey, sign in with a login code from the [command line](/docs/troubleshooting/account-recovery#you-lost-the-admin-passkey) and add one. ## The redirect_uri is not registered for this client [Section titled “The redirect_uri is not registered for this client”](#the-redirect_uri-is-not-registered-for-this-client) Pocket ID only sends users back to the callback URLs listed on the client, and the URL the app sent doesn’t match any of them. The error shows the URL the app sent, so add exactly that one to the client’s **Callback URLs**. A common cause is an app behind a reverse proxy that thinks it runs on `http://` and sends an `http://` callback URL. Configure the app to know its public `https://` address, or as a last resort, add both versions of the URL. ## You are not allowed to access this service [Section titled “You are not allowed to access this service”](#you-are-not-allowed-to-access-this-service) The user isn’t in any of the groups the client allows, and a new client allows no group at all. Add the user to a group on the client’s **Access** tab, or allow all users, as [Allowed user groups](/docs/configuration/allowed-groups) describes. ## The app can’t reach Pocket ID [Section titled “The app can’t reach Pocket ID”](#the-app-cant-reach-pocket-id) Sign-in starts, but the app fails after the redirect back, often with a timeout, a connection error or a TLS error in its logs. The app’s server fetches the discovery document and the tokens from Pocket ID directly, so it has to reach `APP_URL` from where it runs: * `https://id.example.com` has to resolve inside the app’s container, which split-horizon DNS or a missing hairpin NAT on the router can break. * A self-signed or private certificate has to be trusted by the app too. * If the app can only reach Pocket ID at another address, such as `http://pocket-id:1411`, set `INTERNAL_APP_URL` to it. The discovery document then sends the app’s server to that address for tokens, user info and signing keys, while browsers keep using `APP_URL`. The app still has to load the discovery document itself, so give it `http://pocket-id:1411/.well-known/openid-configuration` if it lets you set the discovery URL. ## Content Security Policy errors [Section titled “Content Security Policy errors”](#content-security-policy-errors) The browser console shows an error like this, and parts of Pocket ID don’t load: > Content-Security-Policy: The page’s settings blocked an inline script (script-src-elem) from being executed because it violates the following directive: “script-src ‘self’ … Something in front of Pocket ID injects its own scripts or styles into the page, such as Cloudflare’s **Rocket Loader**. Turn off that feature for the Pocket ID domain. ## nginx returns 502 Bad Gateway [Section titled “nginx returns 502 Bad Gateway”](#nginx-returns-502-bad-gateway) nginx logs `upstream sent too big header`, because Pocket ID’s response headers are larger than nginx’s default buffers. Raise them as in the [nginx example](/docs/setup/reverse-proxy). # Client examples > Step-by-step guides for connecting apps such as Immich, Nextcloud, Jellyfin and Proxmox to Pocket ID with OpenID Connect. Setup guides for apps that sign in with Pocket ID, written by the community. Every app follows the steps of [Connect an app](/docs/setup/connect-an-app), and its guide adds the callback URL and settings it needs. Filter 99 apps * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/actual-budget.svg)Actual Budget](/docs/client-examples/actual-budget) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/adventure-log.svg)AdventureLog](/docs/client-examples/adventure-log) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/airtrail.svg)AirTrail](/docs/client-examples/airtrail) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/arcane.svg)Arcane](/docs/client-examples/arcane) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/attic.svg)Attic](/docs/client-examples/attic) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/audiobookshelf.svg)Audiobookshelf](/docs/client-examples/audiobookshelf) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/beszel.svg)Beszel](/docs/client-examples/beszel) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/bettershift.svg)BetterShift](/docs/client-examples/bettershift) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/blinko.svg)Blinko](/docs/client-examples/blinko) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/bookstack.svg)BookStack](/docs/client-examples/bookstack) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/bytestash.svg)ByteStash](/docs/client-examples/bytestash) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/calibre-web-automated.svg)Calibre-Web Automated](/docs/client-examples/calibre-web-automated) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/certshell.svg)CertShell](/docs/client-examples/certshell) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/cloudflare-zero-trust.svg)Cloudflare Zero Trust](/docs/client-examples/cloudflare-zero-trust) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/dawarich.svg)Dawarich](/docs/client-examples/dawarich) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/dbackup.svg)DBackup](/docs/client-examples/dbackup) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/dockhand.svg)Dockhand](/docs/client-examples/dockhand) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/dolibarr.svg)Dolibarr](/docs/client-examples/dolibarr) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/donetick.svg)Donetick](/docs/client-examples/donetick) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/dozzle.svg)Dozzle](/docs/client-examples/dozzle) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/ezbookkeeping.svg)ezBookkeeping](/docs/client-examples/ezbookkeeping) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/filebrowser-quantum.svg)FileBrowser Quantum](/docs/client-examples/filebrowser-quantum) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/forgejo.svg)Forgejo](/docs/client-examples/forgejo) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/freescout.svg)FreeScout](/docs/client-examples/freescout) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/freshrss.svg)FreshRSS](/docs/client-examples/freshrss) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/gameyfin.svg)Gameyfin](/docs/client-examples/gameyfin) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/gitea.svg)Gitea](/docs/client-examples/gitea) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/gitlab.svg)GitLab](/docs/client-examples/gitlab) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/gotify.svg)Gotify](/docs/client-examples/gotify) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/grafana.svg)Grafana](/docs/client-examples/grafana) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/grist.svg)Grist](/docs/client-examples/grist) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/harbor.svg)Harbor](/docs/client-examples/harbor) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/headscale.svg)Headscale](/docs/client-examples/headscale) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/healthchecks.svg)Healthchecks](/docs/client-examples/healthchecks) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/homarr.svg)Homarr](/docs/client-examples/homarr) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/homebox.svg)HomeBox](/docs/client-examples/homebox) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/immich.svg)Immich](/docs/client-examples/immich) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/inventree.svg)InvenTree](/docs/client-examples/inventree) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/jellyfin.svg)Jellyfin](/docs/client-examples/jellyfin) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/karakeep.svg)Karakeep](/docs/client-examples/karakeep) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/kasm.svg)Kasm Workspaces](/docs/client-examples/kasm) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/kavita.svg)Kavita](/docs/client-examples/kavita) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/komodo.svg)Komodo](/docs/client-examples/komodo) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/linkace.svg)LinkAce](/docs/client-examples/linkace) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/linkding.svg)Linkding](/docs/client-examples/linkding) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/lubelogger.svg)LubeLogger](/docs/client-examples/lubelogger) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/mealie.svg)Mealie](/docs/client-examples/mealie) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/memos.svg)Memos](/docs/client-examples/memos) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/meshcentral.svg)MeshCentral](/docs/client-examples/meshcentral) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/miniflux.svg)Miniflux](/docs/client-examples/miniflux) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/minio.svg)MinIO](/docs/client-examples/minio) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/netbird.svg)NetBird](/docs/client-examples/netbird) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/netbox.svg)NetBox](/docs/client-examples/netbox) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/nextcloud.svg)Nextcloud](/docs/client-examples/nextcloud) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/nextexplorer.svg)nextExplorer](/docs/client-examples/nextexplorer) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/node-red.svg)Node-RED](/docs/client-examples/node-red) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/ocis.svg)oCIS](/docs/client-examples/oCIS) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/open-webui.svg)Open WebUI](/docs/client-examples/open-webui) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/opencloud.svg)OpenCloud](/docs/client-examples/opencloud) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/opengist.svg)Opengist](/docs/client-examples/opengist) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/openpubkeyssh.svg)OpenPubKey SSH](/docs/client-examples/OpenPubKeySSH) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/outline.svg)Outline](/docs/client-examples/outline) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/pangolin.svg)Pangolin](/docs/client-examples/pangolin) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/paperless-ngx.svg)Paperless-ngx](/docs/client-examples/paperless-ngx) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/patchmon.svg)PatchMon](/docs/client-examples/patchmon) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/penpot.svg)Penpot](/docs/client-examples/penpot) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/pgadmin.svg)pgAdmin](/docs/client-examples/pgadmin) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/photoprism.svg)PhotoPrism](/docs/client-examples/photoprism) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/pinepods.svg)Pinepods](/docs/client-examples/pinepods) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/pingvin.svg)Pingvin Share](/docs/client-examples/pingvin) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/planka.svg)Planka](/docs/client-examples/planka) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/portainer.svg)Portainer](/docs/client-examples/portainer) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/postiz.svg)Postiz](/docs/client-examples/postiz) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/proxmox.svg)Proxmox](/docs/client-examples/proxmox) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/proxmox-backup.svg)Proxmox Backup Server](/docs/client-examples/proxmox-backup) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/rallly.svg)Rallly](/docs/client-examples/rallly) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/rdpgw.svg)RDP Gateway](/docs/client-examples/rdpgw) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/readeck.svg)Readeck](/docs/client-examples/readeck) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/readmeabook.svg)ReadMeABook](/docs/client-examples/readmeabook) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/romm.svg)RomM](/docs/client-examples/romm) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/seafile.svg)Seafile](/docs/client-examples/seafile) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/semaphore-ui.svg)Semaphore UI](/docs/client-examples/semaphore-ui) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/sonarqube.svg)SonarQube](/docs/client-examples/sonarqube) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/sonarr.svg)Sonarr](/docs/client-examples/sonarr) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/synology.svg)Synology](/docs/client-examples/synology) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/talos.svg)Talos](/docs/client-examples/talos) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/tandoor-recipes.svg)Tandoor Recipes](/docs/client-examples/tandoor-recipes) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/technitium-dns.svg)Technitium DNS](/docs/client-examples/technitium-dns) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/termix.svg)Termix](/docs/client-examples/termix) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/tududi.svg)tududi](/docs/client-examples/tududi) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/unraid.svg)Unraid](/docs/client-examples/unraid) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/vaultwarden.svg)Vaultwarden](/docs/client-examples/vaultwarden) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/vercel.svg)Vercel](/docs/client-examples/vercel) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/vikunja.svg)Vikunja](/docs/client-examples/vikunja) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/wallos.svg)Wallos](/docs/client-examples/wallos) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/wekan.svg)Wekan](/docs/client-examples/wekan) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/wg-access-server.svg)wg-access-server](/docs/client-examples/wg-access-server) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/wordpress.svg)WordPress](/docs/client-examples/wordpress) * [![](https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/yuvomi.svg)Yuvomi](/docs/client-examples/yuvomi) No guide for that app yet. Most apps only need the client ID, client secret and discovery URL, so the steps of a similar app usually carry over. Missing an app, or found a step that changed? [Add or fix a guide on GitHub](https://github.com/pocket-id/website/tree/main/src/content/docs/docs/client-examples). # Actual Budget > Sign in to the Actual Budget personal finance app with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [Actual Budget](https://actualbudget.org/docs/config/oauth-auth) client and server version `25.1.0` or higher * HTTPS connection to your Actual server ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Actual Budget` and add the callback URL `https://actual.example.com/openid/callback`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Actual using the UI [Section titled “Configure Actual using the UI”](#configure-actual-using-the-ui) 1. Click **Start using OpenID**. 2. Fill in the fields: * **OpenID Provider**: choose `Other`. * **Provider URL**: the **OIDC Discovery URL** from Pocket ID, or the Pocket ID URL (`https://id.example.com`). * **Client ID**: the **Client ID** from Pocket ID. * **Client Secret**: the **Client secret** from Pocket ID. 3. Click **OK** and you will be redirected to the login page. 4. Enter your existing file password and sign in with OpenID to test it. The first user who signs in successfully becomes the administrator. ## Multiple users [Section titled “Multiple users”](#multiple-users) After setting up the integration, you can manage users in Actual by following [these instructions](https://actualbudget.org/docs/config/multi-user). ## Configure Actual with other methods [Section titled “Configure Actual with other methods”](#configure-actual-with-other-methods) You can also configure OpenID with the following methods. Check out Actual’s documentation for more information. * [Environment variables](https://actualbudget.org/docs/config/oauth-auth#configuration-using-environment-variables) * [Configuration file](https://actualbudget.org/docs/config/oauth-auth#configuration-using-a-configuration-file) **Example with `.env`:** ```ini ACTUAL_OPENID_DISCOVERY_URL=https://id.example.com ACTUAL_OPENID_CLIENT_ID= ACTUAL_OPENID_CLIENT_SECRET= ``` **Example with `config.json`:** ```json "openId": { "discoveryURL": "https://id.example.com", "client_id": "", "client_secret": "", "server_hostname": "https://actual.example.com", "authMethod": "openid" // or "oauth2" } ``` # AdventureLog > Sign in to the AdventureLog travel tracker with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [AdventureLog](https://adventurelog.app/docs/configuration/social_auth.html) * HTTPS connection to your AdventureLog server ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `AdventureLog` and add the callback URL `https://adventurelog.example.com/accounts/oidc//login/callback/`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure AdventureLog [Section titled “Configure AdventureLog”](#configure-adventurelog) 1. In AdventureLog, open **User Icon → Admin Settings → Social Accounts → Social applications**. 2. Click **Add Social Application**. 3. Fill in the fields: * **Provider**: choose `OpenID Connect`. * **Provider ID**: the **Client ID** from Pocket ID. * **Name**: `Pocket ID`. * **Client ID**: the **Client ID** from Pocket ID. * **Secret Key**: the **Client secret** from Pocket ID. * **Settings**: `{"server_url": "https://id.example.com/"`. 4. Click the green plus button under **Sites** and add the following: * **Domain Name**: `example.com` (yes, `example.com`, not your domain) * **Display Name**: `example.com` (yes, `example.com`, not your domain) 5. Click `example.com` in the **Available Sites** column and move it to **Chosen sites**. 6. Click **Save**. 7. Open your AdventureLog URL and sign in with Pocket ID to test it. ## Link existing accounts [Section titled “Link existing accounts”](#link-existing-accounts) Users can link their existing accounts manually: 1. Click the profile picture. 2. Click **Settings**. 3. Click **Security**. 4. Select **Launch Account Connections**. 5. Add the account you want to link. # AirTrail > Sign in to the AirTrail flight tracker with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `AirTrail` and add the callback URL `https://airtrail.example.com/login`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure AirTrail through the UI [Section titled “Configure AirTrail through the UI”](#configure-airtrail-through-the-ui) 1. In AirTrail, open **Settings → OAuth**. 2. Turn on **Enable OAuth**. 3. Fill in the fields: * **Issuer URL**: the **OIDC Discovery URL** from Pocket ID. * **Client ID**: the **Client ID** from Pocket ID. * **Client Secret**: the **Client secret** from Pocket ID. 4. Save the settings and sign in with OAuth to test it. ## Configure AirTrail with an `.env` file [Section titled “Configure AirTrail with an .env file”](#configure-airtrail-with-an-env-file) Check out AirTrail’s [documentation](https://airtrail.johan.ohly.dk/docs/features/oauth#configuration) for more details. Example with `.env`: ```ini OAUTH_ENABLED=true OAUTH_ISSUER_URL=https://id.example.com/.well-known/openid-configuration OAUTH_CLIENT_ID= OAUTH_CLIENT_SECRET= ``` # Arcane > Sign in to the Arcane Docker manager with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Arcane` and add the callback URL `https://arcane.example.com/auth/oidc/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. If you use the Arcane iOS app, also add the callback URL `arcane-mobile://oidc-callback`. ## Configure Arcane [Section titled “Configure Arcane”](#configure-arcane) You can set up OIDC in Arcane through the UI or with environment variables. ### UI [Section titled “UI”](#ui) 1. In Arcane, open **Settings → Authentication**. 2. Enter the OIDC provider details: * **Issuer URL**: `https://id.example.com` (no trailing slash). * **Client ID**: the **Client ID** from Pocket ID. * **Client Secret**: the **Client secret** from Pocket ID. 3. Save the settings and test the connection. The UI guides you through any missing or invalid fields. ### Environment variables [Section titled “Environment variables”](#environment-variables) You can also configure OIDC with environment variables in your Arcane compose file: ```ini OIDC_ENABLED=true APP_URL=https://arcane.example.com OIDC_CLIENT_ID="" OIDC_CLIENT_SECRET="" OIDC_ISSUER_URL="https://id.example.com" OIDC_SCOPES="openid email profile groups" OIDC_GROUPS_CLAIM=groups OIDC_ROLE_MAPPINGS=[{"claimValue":"_example_admin_group","roleId":"role_admin"}] ``` Note The example above includes `groups` in the scopes and uses `OIDC_GROUPS_CLAIM` and `OIDC_ROLE_MAPPINGS` to assign roles based on group membership automatically. `OIDC_ROLE_MAPPINGS` takes a JSON array that maps a `claimValue` (the **Name** of a Pocket ID group) to a `roleId` (such as `role_admin`). These variables are optional, and you can omit them if you don’t need automatic role provisioning. # Attic > Sign in to Attic with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [Attic](https://getattic.dev/guides/authentication) version `1.4.0` or higher * HTTPS connection to your Attic server ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Attic` and add the callback URL `https://attic.example.com/auth/oidc/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Attic with environment variables [Section titled “Configure Attic with environment variables”](#configure-attic-with-environment-variables) Add these environment variables to [enable basic](https://getattic.dev/guides/authentication/#basic-oidc-setup) OIDC support: ```ini ATTIC_OIDC_ENABLED=true ATTIC_OIDC_ISSUER_URL=https://id.example.com ATTIC_OIDC_CLIENT_ID= ATTIC_OIDC_CLIENT_SECRET= ``` Caution The `ATTIC_OIDC_ISSUER_URL` must contain only the Pocket ID URL and must not include the `/.well-known/openid-configuration` path. Example: `https://id.example.com` # Audiobookshelf > Sign in to the Audiobookshelf audiobook and podcast server with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Audiobookshelf` and add the callback URLs: ```plaintext https://audiobookshelf.example.com/auth/openid/callback https://audiobookshelf.example.com/auth/openid/mobile-redirect ``` 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Audiobookshelf [Section titled “Configure Audiobookshelf”](#configure-audiobookshelf) 1. Sign in to Audiobookshelf as an admin. 2. Open **Settings → Authentication** and select **OpenID Connect Authentication**. 3. Enter `https://id.example.com` in **Issuer URL** and click **Auto-Populate**. This fills in all the other URL fields. 4. Enter the **Client ID** from Pocket ID. 5. Enter the **Client secret** from Pocket ID. 6. Change **Subfolder for Redirect URLs** to match how you set up Audiobookshelf. In this example, change it to **None** if you use a dedicated subdomain for Audiobookshelf. 7. Set **Match existing users by** to how an OIDC user should be matched with an existing Audiobookshelf user. 8. Turn on **Auto Register** if you want to create a new user when it doesn’t exist yet. 9. *(Optional)* Configure the **Group Claim** (see [Group claim](#group-claim)). Danger If you configure **Group Claim**, users who aren’t in the `admin`, `user` or `guest` group can’t sign in. 10. *(Optional)* Configure the `abspermissions` claim (see [Advanced permission claim](#advanced-permission-claim)). Danger If you configure `abspermissions`, normal users can’t sign in when the claim is missing or invalid. ### Group claim [Section titled “Group claim”](#group-claim) Use this if you want to assign permissions automatically based on group membership. #### Audiobookshelf [Section titled “Audiobookshelf”](#audiobookshelf) Set **Group Claim** under **Settings → Authentication → OpenID Connect Authentication → Group Claim** to `groups`. #### Pocket ID [Section titled “Pocket ID”](#pocket-id) 1. In Pocket ID, open **Administration → User Groups**. 2. Click **Add Group** and create a group with the **Name** `admin`, `user` or `guest`. 3. Add users to the group that matches the permissions you want them to have. ### Advanced permission claim [Section titled “Advanced permission claim”](#advanced-permission-claim) #### Audiobookshelf [Section titled “Audiobookshelf”](#audiobookshelf-1) Set **Advanced Permission Claim** under **Settings → Authentication → OpenID Connect Authentication → Advanced Permission Claim** to `abspermissions`. #### Pocket ID [Section titled “Pocket ID”](#pocket-id-1) 1. In Pocket ID, open **Administration → User Groups** and open the group. 2. Under **Custom Claims**, add a claim with the key `abspermissions`. 3. Set the value to valid JSON like this: ```json { "canDownload": true, "canAccessAllLibraries": true, "canAccessAllTags": true, "tagsAreDenylist": false } ``` 4. Save the custom claims. #### abspermissions fields [Section titled “abspermissions fields”](#abspermissions-fields) ```jsonc { "canDownload": false, //Allows a user to download content "canUpload": false, //Allows a user to Upload content "canDelete": false, //Allows a user to delete content "canUpdate": false, "canAccessExplicitContent": false, //Allow access to explicit content "canAccessAllLibraries": false, //Allow access to all Libraries (only set to true if nothing is specified below) "canAccessAllTags": false, //Allow access to all tags (only set to true if nothing is specified below) "canCreateEReader": false, "tagsAreDenylist": false, //Invert the allowed tags list to a deny list "allowedLibraries": [ //Specify which libraries are allowed to be accessed via the library ID "5406ba8a-16e1-451d-96d7-4931b0a0d966", //You can get this ID via the Audiobookshelf api "918fd848-7c1d-4a02-818a-847435a879ca" //https://audiobookshelf.example.com/api/libraries ], "allowedTags": [ //Specify which tags are allowed (or denied) "Romance", "Fantasy", "ThirdTag" ] } ``` ## Sources [Section titled “Sources”](#sources) * * * # Beszel > Sign in to the Beszel server monitoring hub with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [Beszel server](https://www.beszel.dev/guide/oauth) * HTTPS connection to your Beszel server ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Beszel` and add the callback URL `https://beszel.example.com/api/oauth2-redirect`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL**, the **Token URL** and the **Userinfo URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Verify emails in Pocket ID [Section titled “Verify emails in Pocket ID”](#verify-emails-in-pocket-id) 1. In Pocket ID, open **Administration → Application Configuration → Email** and turn on **Emails verified by default**. 2. Open **Administration → Users** and select the user account. Make sure the email address is marked as verified. If the icon next to the email isn’t green, click it to mark the email as verified. Note Beszel requires the OAuth provider to return a valid, verified email address to create new users. If you see an error like `Failed to create record. { "email": "cannot be blank" }`, your OAuth provider isn’t returning a usable email. Make sure **Emails verified by default** is turned on in Pocket ID, or that your identity provider returns a verified email in its `userinfo` response. ## Configure Beszel [Section titled “Configure Beszel”](#configure-beszel) 1. Open the Beszel superuser interface (`/_/#/settings`) and go to **Settings → Application**. 2. Turn off **Hide collection create and edit controls**. 3. Go to **Collections → Users**. 4. Edit the `users` collection with the gear icon next to the title. 5. Go to **Options → OAuth2**. 6. Select **Active** and click **Add provider**. 7. Select the `oidc` provider. 8. Fill in the fields with the values from Pocket ID: * **Client ID**: the **Client ID** from Pocket ID. * **Client Secret**: the **Client secret** from Pocket ID. * **Display Name**: a name of your choice, such as `Pocket`. * **Auth URL**: the **Authorization URL** from Pocket ID. * **Token URL**: the **Token URL** from Pocket ID. * **Fetch user info from**: `User info URL`, then enter the **Userinfo URL** from Pocket ID. * Leave **Support PKCE** turned on. 9. Save the settings. 10. Turn **Hide collection create and edit controls** from step 2 back on, then sign in with Pocket ID to test it. ### Disable password login [Section titled “Disable password login”](#disable-password-login) To disable password login, set `DISABLE_PASSWORD_AUTH=true` in the hub environment variables. If you only change it in the UI, the value is overwritten on the next restart. ### Automatic user creation [Section titled “Automatic user creation”](#automatic-user-creation) Beszel doesn’t allow automatic user creation by default. To enable it, set `USER_CREATION=true` in the hub environment variables. ## Sources [Section titled “Sources”](#sources) [Beszel Configuration Guide](https://www.beszel.dev/guide/oauth) # BetterShift > Sign in to the BetterShift shift planner with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `BetterShift` and add the callback URL `https://bettershift.example.com/api/auth/oauth2/callback/custom-oidc`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure BetterShift [Section titled “Configure BetterShift”](#configure-bettershift) Add or edit the following lines in your BetterShift `.env` file, using the values you copied from Pocket ID: ```ini CUSTOM_OIDC_ENABLED=true CUSTOM_OIDC_NAME=Login with Pocket ID # BUTTON_TEXT CUSTOM_OIDC_CLIENT_ID= CUSTOM_OIDC_CLIENT_SECRET= CUSTOM_OIDC_ISSUER=https://id.example.com/.well-known/openid-configuration CUSTOM_OIDC_SCOPES=openid profile email # Space-separated list ``` Save the file, redeploy BetterShift and sign in with Pocket ID to test it. ## Sources [Section titled “Sources”](#sources) * * # Blinko > Sign in to the Blinko note-taking app with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * A self-hosted [Blinko](https://github.com/blinkospace/blinko) instance. * Administrator access to both Blinko and Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Blinko` and add the callback URL `https://blinko.example.com/api/auth/callback/pocket-id`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Blinko [Section titled “Configure Blinko”](#configure-blinko) 1. Sign in to Blinko as an admin. 2. Open **Settings → SSO Settings** and click **Add Provider**. 3. Set **Provider** to `Custom Provider`. 4. Configure the provider details: * **Provider ID**: `pocket-id`. This must match the end of the callback URL you added in Pocket ID. * **Provider Name**: `Pocket ID` (or your preferred display name). * **Provider Icon**: *(Optional)* an icon string, such as `streamline-ultimate:touch-id-bold`. 5. Paste the **OIDC Discovery URL** from Pocket ID into the **WellKnown URL** field, for example `https://id.example.com/.well-known/openid-configuration`. The authorization, token and userinfo URLs are fetched automatically. If they aren’t, copy them from the client’s page in Pocket ID under **Show more details**. The scopes are `openid email profile groups`. 6. Enter the **Client ID** and the **Client secret** from Pocket ID. 7. Save the settings and sign in with Pocket ID to test it. Note To link an existing Blinko account to your SSO account, follow the [official instructions](https://docs.blinko.space/en/settings/link-account). # BookStack > Sign in to the BookStack wiki with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `BookStack` and add the callback URL `https://bookstack.example.com/oidc/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, turn on **PKCE**, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure BookStack [Section titled “Configure BookStack”](#configure-bookstack) Refer to the BookStack [documentation](https://www.bookstackapp.com/docs/admin/oidc-auth/) for more information if needed. Add the following variables to the `.env` file of your BookStack container and restart it: ```ini AUTH_METHOD=oidc AUTH_AUTO_INITIATE=true OIDC_NAME="Pocket ID" OIDC_DISPLAY_NAME_CLAIMS=name OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= OIDC_ISSUER=https://id.example.com OIDC_END_SESSION_ENDPOINT=true OIDC_ISSUER_DISCOVER=true ``` ### Group synchronization [Section titled “Group synchronization”](#group-synchronization) BookStack can sync OIDC user groups with BookStack roles. By default, BookStack matches OIDC groups (Pocket ID groups) with the display names of BookStack roles, ignoring case. This feature requires the OIDC server to provide a claim in the ID token with an array of group names. 1. Set up new **Roles** (or rename existing ones) in BookStack, for example: * BookStack_Admin * BookStack_Editor * BookStack_Viewer 2. In Pocket ID, open **Administration → User Groups** and create matching groups with **Add Group** (**Friendly Name** and **Name**): * BookStack Admin (`bookstack_admin`) * BookStack Editor (`bookstack_editor`) * BookStack Viewer (`bookstack_viewer`) 3. Add the following lines to the `.env` file of your BookStack container and restart it: ```ini OIDC_USER_TO_GROUPS=true OIDC_GROUPS_CLAIM=groups OIDC_ADDITIONAL_SCOPES=groups OIDC_REMOVE_FROM_GROUPS=true ``` # ByteStash > Sign in to the ByteStash code snippet manager with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `ByteStash` and add the callback URL `https://bytestash.example.com/api/oauth/openid`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure ByteStash [Section titled “Configure ByteStash”](#configure-bytestash) 1. Set the following ByteStash environment variables: * `OIDC_ENABLED`: `true` to enable OIDC authentication. * `OIDC_DISPLAY_NAME`: the lowercase name of the provider (`pocketid`). * `OIDC_ISSUER_URL`: the URL of your Pocket ID instance, such as `https://id.example.com`. * `OIDC_CLIENT_ID`: the **Client ID** from Pocket ID. * `OIDC_CLIENT_SECRET`: the **Client secret** from Pocket ID. 2. Set up your email address in ByteStash. It has to match your email address in Pocket ID. # Calibre-Web Automated > Sign in to the Calibre-Web Automated e-book library with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Calibre-Web Automated` and add the callback URL `https://calibre-web-automated.example.com/login/generic/authorized`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Calibre-Web Automated through the UI [Section titled “Configure Calibre-Web Automated through the UI”](#configure-calibre-web-automated-through-the-ui) 1. In Calibre-Web Automated, open **Admin Settings → Edit Basic Configuration**. 2. Under **Feature Configuration → Login type**, select `Use OAuth (requires HTTPS)`. 3. Fill in the fields: * **OAuth Metadata URL**: the **OIDC Discovery URL** from Pocket ID. * **OAuth Client ID**: the **Client ID** from Pocket ID. * **OAuth Client Secret**: the **Client secret** from Pocket ID. 4. Save the settings and sign in with OAuth to test it. # CertShell > Sign in to the CertShell browser SSH terminal with Pocket ID, and use Pocket ID groups to decide who can reach which hosts. ## Requirements [Section titled “Requirements”](#requirements) * [CertShell](https://github.com/maca134/certshell) reachable over HTTPS, e.g. `https://ssh.example.com` * A user group in Pocket ID for CertShell admins, `certshell-admins` by default ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `CertShell` and add the callback URL `https://ssh.example.com/auth/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Issuer URL**. The client secret is only shown once. 4. On the client’s **General** tab, turn on **PKCE**, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure CertShell [Section titled “Configure CertShell”](#configure-certshell) 1. Add the values to CertShell’s `.env`: ```ini APP_URL=https://ssh.example.com OIDC_ISSUER=https://id.example.com OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= ``` 2. Restart CertShell and sign in. Members of `certshell-admins` (set another name with `OIDC_ADMIN_GROUP`) see the **Admin** section. 3. In CertShell, open **Admin → Hosts** and allow your Pocket ID groups on each host’s logins. Note CertShell matches a group’s **name**, not its friendly name. Group changes apply at the user’s next CertShell sign-in. # Cloudflare Zero Trust > Use Pocket ID as an identity provider for Cloudflare Zero Trust Access. Caution Cloudflare needs to be able to reach your Pocket ID instance and vice versa for this to work correctly. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Cloudflare Zero Trust` and add the callback URL `https://.cloudflareaccess.com/cdn-cgi/access/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL**, the **Token URL** and the **Certificate URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Cloudflare Zero Trust [Section titled “Configure Cloudflare Zero Trust”](#configure-cloudflare-zero-trust) 1. Sign in to the Cloudflare Zero Trust [dashboard](https://one.dash.cloudflare.com/). 2. In the left navigation, go to **Integrations → Identity providers**. 3. Under **Identity provider integrations**, click **Add an identity provider**. 4. Choose **OpenID Connect** as the identity provider. 5. Enter a name for the new login method. 6. Fill in the fields: * **App ID**: the **Client ID** from Pocket ID. * **Client Secret**: the **Client secret** from Pocket ID. * **Auth URL**: the **Authorization URL** from Pocket ID. * **Token URL**: the **Token URL** from Pocket ID. * **Certificate URL**: the **Certificate URL** from Pocket ID. 7. Save the new login method and test it in Cloudflare. # Dawarich > Sign in to the Dawarich location history tracker with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [Dawarich](https://github.com/Freika/dawarich/releases/tag/0.36.0) version `0.36.0` or higher * Pocket ID on HTTPS, reachable at `https://id.example.com` * Dawarich server on HTTPS, reachable at `https://dawarich.example.com` ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Dawarich` and add the callback URL `https://dawarich.example.com/users/auth/openid_connect/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, set **Client Launch URL** to `https://dawarich.example.com`, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. Keep **PKCE** turned off if you get errors. ## Configure Dawarich [Section titled “Configure Dawarich”](#configure-dawarich) This is the minimal configuration needed to set up Pocket ID with Dawarich. 1. Add the following lines to your Dawarich `.env`/`docker-compose.yml` file, replacing the values with the ones you copied in step 3 above: ```ini OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= OIDC_ISSUER=https://id.example.com/.well-known/openid-configuration OIDC_REDIRECT_URI=https://dawarich.example.com/users/auth/openid_connect/callback ``` 2. Save the file and restart the Dawarich Docker Compose stack. # DBackup > Sign in to the DBackup database backup tool with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `DBackup` and add the callback URL `https://dbackup.example.com/api/auth/sso/callback/`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. `` must be the **Provider ID** you get when you create the SSO/OIDC settings in DBackup. DBackup proposes an ID such as `pocket-id-1234`. In a local Docker installation of DBackup, the callback URL can also use the local IP address and port of DBackup, for example `https://192.168.x.xxx:3000/api/auth/sso/callback/pocket-id-123`. ## Configure DBackup [Section titled “Configure DBackup”](#configure-dbackup) The SSO settings in DBackup are under **Users & Groups → SSO / OIDC**. | Field | Description | Example | | ------------- | -------------------------------------------- | ------------------------ | | Name | Display name | `"Pocket ID"` | | Provider ID | The ID used in the callback URL in Pocket ID | `pocket-id-1234` | | Provider | Pocket ID URL | `https://id.example.com` | | Client ID | The **Client ID** from Pocket ID | `` | | Client Secret | The **Client secret** from Pocket ID | `` | # Dockhand > Sign in to Dockhand with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Dockhand` and add the callback URL `https://dockhand.example.com/api/auth/oidc/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. For a local Docker installation of Dockhand, the callback URL can also use the local IP address with `http` and the Dockhand port, for example `http://192.168.x.xxx:3866/api/auth/oidc/callback`. ## Configure Dockhand [Section titled “Configure Dockhand”](#configure-dockhand) 1. In Dockhand, open **Settings → Authentication → SSO / OIDC** and click **+Add Provider**. 2. Fill in the fields: | Field | Description | Example | | ------------------ | --------------------------------------- | ----------------------------------------------------- | | Name | Display name | `Pocket ID` | | Issuer URL | The URL of Pocket ID | `https://id.example.com` | | Client ID | The **Client ID** from Pocket ID | `` | | Client Secret | The **Client secret** from Pocket ID | `` | | Redirect URI | The callback URL you added in Pocket ID | `https://dockhand.example.com/api/auth/oidc/callback` | | Scopes | Scopes requested from Pocket ID | `openid profile email` | | Username claim | Username claim | `preferred_username` | | Email claim | Email claim | `email` | | Display name claim | Display name claim | `name` | When you access a local Dockhand installation, the **Redirect URI** in the Dockhand SSO / OIDC settings can be `http://192.168.x.xxx:3866/api/auth/oidc/callback` without HTTPS. # Dolibarr > Sign in to the Dolibarr ERP and CRM with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Dolibarr` and add the callback URL `https://dolibarr.example.com/core/modules/openid_connect/callback.php`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL**, the **Token URL**, the **Userinfo URL** and the **Logout URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Dolibarr [Section titled “Configure Dolibarr”](#configure-dolibarr) Caution The email addresses of the Pocket ID and Dolibarr accounts must match. 1. Log in to Dolibarr as the admin user. 2. Open **Home → Setup → Security** and select **OpenID authentication parameters**. 3. Fill in the fields: * **Display Name**: `Pocket ID` or something similar. * **Client Id**: the **Client ID** from Pocket ID. * **Client secret**: the **Client secret** from Pocket ID. * **Scopes**: `openid profile email` * **Authorize URL**: the **Authorization URL** from Pocket ID. * **Token URL**: the **Token URL** from Pocket ID. * **User info URL**: the **Userinfo URL** from Pocket ID. * **Logout URL**: the **Logout URL** from Pocket ID. 4. In the file `conf.php`, replace the current value of `dolibarr_main_authentication` with `openid_connect,dolibarr`. 5. Log out and sign in with Pocket ID to test it. # Donetick > Sign in to the Donetick task manager with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Donetick` and add the callback URL `https://donetick.example.com/auth/oauth2`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL**, the **Token URL** and the **Userinfo URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Donetick [Section titled “Configure Donetick”](#configure-donetick) 1. In the Donetick configuration file `selfhosted.yaml`, fill in the `oauth2` fields: ```yaml oauth2: client_id: client_secret: auth_url: https://id.example.com/authorize token_url: https://id.example.com/api/oidc/token user_info_url: https://id.example.com/api/oidc/userinfo redirect_url: https://donetick.example.com/auth/oauth2 name: Pocket ID ``` 2. Restart your Donetick container and you’re good to go. # Dozzle > Sign in to the Dozzle log viewer with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [Dozzle](https://github.com/amir20/dozzle) * HTTPS connection to your Pocket ID server Dozzle supports OIDC natively, so there is no need for a middleware proxy anymore. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Dozzle` and add the callback URL `https://dozzle.example.com/api/auth/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Dozzle [Section titled “Configure Dozzle”](#configure-dozzle) 1. Add the following to your existing Dozzle compose or `.env` file: ```yaml environment: DOZZLE_AUTH_PROVIDER: oidc # do not change. DOZZLE_AUTH_OIDC_NAME: pocket-id # this is just a visual control to set the label in the login button, It is not necessary. DOZZLE_AUTH_OIDC_ISSUER: https://id.example.com # base domain only, dozzle will automatically fetch the well-known endpoint. DOZZLE_AUTH_OIDC_CLIENT_IDL: DOZZLE_AUTH_OIDC_CLIENT_SECRET: ``` 2. Dozzle requires a custom claim to allow login. For each user you want to grant access to Dozzle: * In Pocket ID, open **Administration → Users** and click the user. * Under **Custom Claims**, add the key `dozzle_roles` with a value such as `all,^shell`. This grants full access to the user, minus the ability to attach a shell to containers, for security reasons. For the possible values of `dozzle_roles`, see the [Dozzle docs](https://dozzle.dev/guide/authentication/oidc#roles). 3. Restart your Docker Compose stack, and make sure the container is recreated to pick up the environment changes. # ezBookkeeping > Sign in to the ezBookkeeping finance app with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [ezBookkeeping](https://ezbookkeeping.mayswind.net/) `v1.2.0` or higher ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `ezBookkeeping` and add the callback URL `https://ezbookkeeping.example.com/oauth2/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Issuer URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure ezBookkeeping [Section titled “Configure ezBookkeeping”](#configure-ezbookkeeping) If you configure ezBookkeeping with the configuration file, update it as shown in the example below: ```ini [auth] enable_oauth2_auth = true oauth2_provider = oidc oauth2_client_id = oauth2_client_secret = oidc_provider_base_url = https://id.example.com enable_oidc_display_name = true oidc_custom_display_name = Pocket ID ``` If you configure ezBookkeeping with environment variables, set them as shown in the example below: ```ini EBK_AUTH_ENABLE_OAUTH2_AUTH=true EBK_AUTH_OAUTH2_PROVIDER=oidc EBK_AUTH_OAUTH2_CLIENT_ID= EBK_AUTH_OAUTH2_CLIENT_SECRET= EBK_AUTH_OIDC_PROVIDER_BASE_URL=https://id.example.com EBK_AUTH_ENABLE_OIDC_DISPLAY_NAME=true EBK_AUTH_OIDC_CUSTOM_DISPLAY_NAME=Pocket ID ``` Then restart ezBookkeeping. The login page now shows a **Log in with Pocket ID** button. # FileBrowser Quantum > Sign in to the FileBrowser Quantum file manager with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [FileBrowser Quantum](https://github.com/gtsteffaniak/filebrowser/wiki/Configuration-And-Examples#openid-connect-configuration-oidc) with [SSO](https://github.com/gtsteffaniak/filebrowser/issues/816#issuecomment-2993195649) * HTTPS connection to your Pocket ID server ## Create groups in Pocket ID [Section titled “Create groups in Pocket ID”](#create-groups-in-pocket-id) 1. *(Optional)* To limit access to specific users, open **Administration → User Groups** in Pocket ID, click **Add Group** and create a group with the **Name** `filebrowser`. Add the users who may sign in to it. 2. *(Optional)* To grant admin privileges based on group, create a second group with the **Name** `filebrowser_admin` and add the admin users to it. Copy the group name for the FileBrowser Quantum configuration. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `FileBrowser Quantum`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the `filebrowser` group under **Allowed User Groups**, or choose **All Users**. ## Configure FileBrowser Quantum [Section titled “Configure FileBrowser Quantum”](#configure-filebrowser-quantum) Add the following to your `config.yaml`, replacing values where applicable: ```yaml auth: methods: oidc: enabled: true clientId: clientSecret: issuerUrl: https://id.example.com scopes: email openid profile groups userIdentifier: preferred_username disableVerifyTLS: false createUser: true # Below is optional. Also add 'groups' to 'scopes' if using this adminGroup: filebrowser_admin ``` To disable local password authentication, also add: ```yaml auth: methods: password: enabled: false ``` # Forgejo > Sign in to the Forgejo Git service with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Forgejo` and add the callback URL `https://forgejo.example.com/user/oauth2/PocketID/callback`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Forgejo [Section titled “Configure Forgejo”](#configure-forgejo) 1. Log in to Forgejo as an admin. 2. Open **Site Administration → Identity & Access → Authentication Sources**. 3. Click **Add Authentication Source**. 4. Set **Authentication Type** to `OAuth2`. 5. Set **Authentication Name** to `PocketID`. Caution If you change this name, update the callback URL in Pocket ID to match. 6. Set **OAuth2 Provider** to `OpenID Connect`. 7. Enter the **Client ID** from Pocket ID into the **Client ID (Key)** field. 8. Enter the **Client secret** from Pocket ID into the **Client Secret** field. 9. Enter the **OIDC Discovery URL** from Pocket ID into the **OpenID Connect Auto Discovery URL** field. 10. Enable **Skip local 2FA**. 11. Set **Additional Scopes** to `openid email profile`. 12. Save the settings and sign in with Pocket ID to test it. # FreeScout > Sign in to the FreeScout help desk with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [FreeScout OAuth Social Login Module](https://freescout.net/module/oauth-login/) (one-time fee) * HTTPS connection to your FreeScout server ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `FreeScout` and add the callback URL `https://freescout.example.com/oauth-login/callback/*`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL**, the **Token URL** and the **Userinfo URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. After creating the OAuth provider in FreeScout, replace the callback URL with the exact **Redirect URI** generated by FreeScout. ## Configure FreeScout [Section titled “Configure FreeScout”](#configure-freescout) 1. In FreeScout, open **Manage → Settings → OAuth**. 2. Enable the **Active** checkmark. 3. Fill in the required fields: * **Provider**: `Custom Oauth Provider` * **Name**: `Pocket ID` or similar. * **Redirect URI**: copy this value into the **Callback URLs** of the client in Pocket ID, replacing the one you added earlier. * **Logout URI**: leave the generated value provided by FreeScout. * **Client ID**: the **Client ID** from Pocket ID. * **Client Secret**: the **Client secret** from Pocket ID. * **Authorization URL**: the **Authorization URL** from Pocket ID. * **Token URL**: the **Token URL** from Pocket ID. * **User Info URL**: the **Userinfo URL** from Pocket ID. * **User Info Method**: `POST` * **Proxy URL, Field Mappings, Scopes**: leave blank unless your environment needs them. 4. Save the settings and sign in with Pocket ID to test it. ### Optional settings [Section titled “Optional settings”](#optional-settings) * Enable **Auto-Create Users** to create users in FreeScout automatically when they sign in with Pocket ID for the first time. * Enable **Force OAuth Login** to force sign-in with Pocket ID. Don’t enable this until you have fully tested the setup. To disable it again, see the [module documentation](https://freescout.net/module/oauth-login/). * Enable **Debug Mode** to examine the OAuth transaction in the FreeScout logs. You can disable it again after testing. # FreshRSS > Sign in to the FreshRSS feed reader with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `FreshRSS` and add the callback URL `https://freshrss.example.com/i/oidc/`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure FreshRSS [Section titled “Configure FreshRSS”](#configure-freshrss) See [FreshRSS’ OpenID Connect documentation](https://freshrss.github.io/FreshRSS/en/admins/16_OpenID-Connect.html) for specific FreshRSS OIDC settings. This is an example Docker Compose file for FreshRSS with OIDC enabled: ```yaml services: freshrss: image: freshrss/freshrss:1.25.0 container_name: freshrss ports: - 8080:80 volumes: - /freshrss_data:/var/www/FreshRSS/data - /freshrss_extensions:/var/www/FreshRSS/extensions environment: CRON_MIN: 1,31 TZ: Etc/UTC OIDC_ENABLED: 1 OIDC_CLIENT_ID: OIDC_CLIENT_SECRET: OIDC_PROVIDER_METADATA_URL: https://id.example.com/.well-known/openid-configuration OIDC_SCOPES: openid email profile OIDC_X_FORWARDED_HEADERS: X-Forwarded-Proto X-Forwarded-Host OIDC_REMOTE_USER_CLAIM: preferred_username restart: unless-stopped networks: - freshrss networks: freshrss: name: freshrss ``` Caution The username in Pocket ID must match the username in FreshRSS **exactly**, including case. As of version `0.24` of Pocket ID, all usernames must be entirely lowercase, while FreshRSS allows uppercase. If a Pocket ID username is `amanda` and your FreshRSS username is `Amanda`, you will get a 403 error in FreshRSS and be unable to log in. As of version `1.25` of FreshRSS, you can’t change your username in the GUI. To change your FreshRSS username to lowercase or to match your Pocket ID username, go to your FreshRSS volume location. In `data/users/`, rename the folder for your user to the matching username in Pocket ID, then restart the FreshRSS container to apply the changes. ## Complete the setup [Section titled “Complete the setup”](#complete-the-setup) If you are setting up a new instance of FreshRSS, start the container with the OIDC variables and open your FreshRSS URL. If you are adding OIDC to an existing FreshRSS instance, recreate the container with the Docker Compose file that contains the OIDC variables and open your FreshRSS URL. Open **Settings → Authentication**, change the authentication method to **HTTP** and click **Submit**. Log out to test your OIDC connection. If you get an error from Pocket ID or can’t log in to your FreshRSS account, you can revert to password login by editing the FreshRSS `config.php` file. Find the value for `auth_type` and change it from `http_auth` to `form`. Restart the FreshRSS container to revert to password login. # Gameyfin > Sign in to the Gameyfin game library manager with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Gameyfin` and add the callback URL `https://gameyfin.example.com/login/oauth2/code/oidc`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Issuer URL**, the **Authorization URL**, the **Token URL**, the **Userinfo URL**, the **Logout URL** and the **Certificate URL**. The client secret is only shown once. 4. On the client’s **General** tab, set **Client Launch URL** to `https://gameyfin.example.com/login`, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Create groups in Pocket ID [Section titled “Create groups in Pocket ID”](#create-groups-in-pocket-id) 1. In Pocket ID, open **Administration → User Groups** and click **Add Group** to create two groups, one for `superadmins` and one for `admins`: * **Friendly Name**: fill out to your liking. * **Name**: use the generated one or change it if you want. 2. Save each group, then add a custom claim on each group’s page under **Custom Claims**: * **Key**: `roles` * **Value**: `["GAMEYFIN_SUPERADMIN"]` for the superadmin group and `["GAMEYFIN_ADMIN"]` for the admin group. 3. Save the custom claim. 4. Add your users to their respective groups in Pocket ID. Users that are in neither group are automatically assigned the “User” role. ## Configure Gameyfin [Section titled “Configure Gameyfin”](#configure-gameyfin) 1. Open Gameyfin’s SSO settings page (**Administration → SSO**), enable SSO and fill out the SSO provider configuration with the values from Pocket ID. You can use **Auto-populate** to fill most of the values automatically, or copy them manually from Pocket ID. * **Client ID**: the **Client ID** from Pocket ID. * **Client secret**: the **Client secret** from Pocket ID. * **Issuer URL**: the **Issuer URL** from Pocket ID, for example `https://id.example.com`, without a trailing slash. * **Authorize URL**: the **Authorization URL** from Pocket ID. * **Token URL**: the **Token URL** from Pocket ID. * **Userinfo URL**: the **Userinfo URL** from Pocket ID. * **Logout URL**: the **Logout URL** from Pocket ID. * **JWKS URL**: the **Certificate URL** from Pocket ID. 2. Restart Gameyfin. # Gitea > Sign in to the Gitea Git service with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Gitea` and add the callback URL `https://gitea.example.com/user/oauth2/PocketID/callback`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Gitea [Section titled “Configure Gitea”](#configure-gitea) 1. Log in to Gitea as an admin. 2. Open **Site Administration → Identity & Access → Authentication Sources**. 3. Click **Add Authentication Source**. 4. Set **Authentication Type** to `OAuth2`. 5. Set **Authentication Name** to `PocketID`. Caution If you change this name, update the callback URL in Pocket ID to match. 6. Set **OAuth2 Provider** to `OpenID Connect`. 7. Enter the **Client ID** from Pocket ID into the **Client ID (Key)** field. 8. Enter the **Client secret** from Pocket ID into the **Client Secret** field. 9. Enter the **OIDC Discovery URL** from Pocket ID into the **OpenID Connect Auto Discovery URL** field. 10. Enable **Skip local 2FA**. 11. Set **Additional Scopes** to `openid email profile`. 12. Save the settings and sign in with Pocket ID to test it. # GitLab > Sign in to GitLab with Pocket ID. Setting up GitLab requires access to the GitLab configuration file (most likely `/etc/gitlab/gitlab.rb`) as well as shell access for reconfiguring. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `GitLab` and add the callback URL `https://gitlab.example.com/users/auth/openid_connect/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure GitLab [Section titled “Configure GitLab”](#configure-gitlab) See the GitLab documentation for [OmniAuth](https://docs.gitlab.com/integration/omniauth/) for more information on OmniAuth. More detailed information on the available OIDC features, such as group assignment, is [here](https://docs.gitlab.com/administration/auth/oidc/). 1. Open the config file in an editor of your choice. 2. Find the `OmniAuth` section of the config file (around line 579). You can do the next steps by either uncommenting the options or adding new ones. 3. Enable OmniAuth: `gitlab_rails['omniauth_enabled'] = true` 4. Allow single sign-on: `gitlab_rails['omniauth_allow_single_sign_on] = ['openid_connect']` 5. Create a new provider: ```ruby gitlab_rails['omniauth_providers'] = [ { name: "openid_connect", label: "Pocket ID", icon: "https://id.example.com/api/application-images/logo", args: { name: "openid_connect", scope: ["openid","profile","email"], response_type: "code", issuer: "https://id.example.com", discovery: true, client_auth_method: "query", uid_field: "preferred_username", send_scope_to_token_endpoint: "false", pkce: true, client_options: { identifier: "", secret: "", redirect_uri: "https://gitlab.example.com/users/auth/openid_connect/callback" } } } ] ``` 6. After completing these edits to the configuration file, reconfigure GitLab: ```bash gitlab-ctl reconfigure ``` ## Existing accounts [Section titled “Existing accounts”](#existing-accounts) After enabling OIDC, existing users need to sign in with their username and password and then link their Pocket ID account. They can do this on the **Profile → Account** page (`https://gitlab.example.com/-/profile/account`). Under **Service sign-in**, there is a **Connect Pocket ID** button to sign in with Pocket ID. After that, they can sign in with Pocket ID on the sign-in page. ## New accounts [Section titled “New accounts”](#new-accounts) Depending on your GitLab instance’s policies, your administrator may need to provision or enable each new account as it is created. # Gotify > Sign in to the Gotify notification server with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * Gotify Server version `3.0` or higher ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Gotify` and add the callback URLs: ```plaintext https://gotify.example.com/auth/oidc/callback gotify://oidc/callback ``` 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, turn on **PKCE**, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. The `gotify://oidc/callback` URL is only needed for the Android app. ## Configure Gotify [Section titled “Configure Gotify”](#configure-gotify) [OIDC for Gotify is configured with environment variables](https://gotify.net/docs/config). There is no GUI for managing it. Depending on the installation method, these variables need to be passed in different ways. However, the same variables are used in every case, and [they are all referenced in Gotify’s docs](https://gotify.net/docs/oidc). For Docker deployments, use Docker environment variables. Set the following variables, replacing `gotify.example.com` and `id.example.com` with your own domains: ```ini GOTIFY_OIDC_ENABLED=true GOTIFY_OIDC_ISSUER=https://id.example.com GOTIFY_OIDC_CLIENTID= GOTIFY_OIDC_CLIENTSECRET= GOTIFY_OIDC_REDIRECTURL=https://gotify.example.com/auth/oidc/callback GOTIFY_OIDC_AUTOREGISTER=true GOTIFY_OIDC_USERNAMECLAIM=preferred_username GOTIFY_OIDC_LINK_BY_USERNAME=false GOTIFY_OIDC_SCOPES=openid,profile,email ``` Where: * **`GOTIFY_OIDC_CLIENTID`**: the **Client ID** from Pocket ID. * **`GOTIFY_OIDC_CLIENTSECRET`**: the **Client secret** from Pocket ID. * **`GOTIFY_OIDC_AUTOREGISTER`**: can be set to `false` to disable auto-provisioning. * **`GOTIFY_OIDC_LINK_BY_USERNAME`**: can be set to `true` if you want your Pocket ID user to be mapped to an already existing internal Gotify user with the same username. ### Docker Compose example [Section titled “Docker Compose example”](#docker-compose-example) ```yaml services: gotify: container_name: gotify restart: unless-stopped image: gotify/server ports: - 8080:80 volumes: - gotify-data:/app/data environment: - GOTIFY_OIDC_ENABLED=true - GOTIFY_OIDC_ISSUER=https://id.example.com - GOTIFY_OIDC_CLIENTID= - GOTIFY_OIDC_CLIENTSECRET= - GOTIFY_OIDC_REDIRECTURL=https://gotify.example.com/auth/oidc/callback - GOTIFY_OIDC_AUTOREGISTER=true - GOTIFY_OIDC_USERNAMECLAIM=preferred_username - GOTIFY_OIDC_LINK_BY_USERNAME=false - GOTIFY_OIDC_SCOPES=openid,profile,email ``` ### Docker run example [Section titled “Docker run example”](#docker-run-example) ```bash docker run -d --name gotify --restart unless-stopped \ -p 8080:80 \ -v gotify-data:/app/data \ -e GOTIFY_OIDC_ENABLED=true \ -e GOTIFY_OIDC_ISSUER=https://id.example.com \ -e GOTIFY_OIDC_CLIENTID= \ -e GOTIFY_OIDC_CLIENTSECRET= \ -e GOTIFY_OIDC_REDIRECTURL=https://gotify.example.com/auth/oidc/callback \ -e GOTIFY_OIDC_AUTOREGISTER=true \ -e GOTIFY_OIDC_USERNAMECLAIM=preferred_username \ -e GOTIFY_OIDC_LINK_BY_USERNAME=false \ -e GOTIFY_OIDC_SCOPES="openid,profile,email" \ gotify/server ``` # Grafana > Sign in to Grafana with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Grafana` and add the callback URL `https://grafana.example.com/login/generic_oauth`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL** and the **Token URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Grafana [Section titled “Configure Grafana”](#configure-grafana) 1. Log in to Grafana as the admin user. 2. Open **Administration → Authentication** and select **Generic OAuth**. 3. Under **General Settings**, fill in the fields: * **Display Name**: `Pocket ID` or something similar. * **Client Id**: the **Client ID** from Pocket ID. * **Client secret**: the **Client secret** from Pocket ID. * **Auth style**: `Auto Detect` * **Scopes**: `openid`, `email` and `profile` * **Auth URL**: the **Authorization URL** from Pocket ID. * **Token URL**: the **Token URL** from Pocket ID. * Leave **API URL** and **Sign out redirect URL** empty. * Leave **Allow sign up** and **Auto login** disabled. 4. Under **User mapping**: * Only set **Email attribute name** to `email:primary` and leave all other fields empty. * Only enable **Skip organization role sync** and leave the other toggles disabled. 5. Nothing needs to be done under **Extra security measures**. 6. Save the settings. 7. Create a new admin user or update the existing admin user under **Users** so that it has the same email address as your user in Pocket ID. Also set the username to the same email address. 8. Log out and sign in with Pocket ID to test it. ## Role mapping [Section titled “Role mapping”](#role-mapping) To assign roles automatically based on group membership: 1. Add `groups` to the **Scopes** setting: `openid email profile groups` 2. Set the **role attribute path** according to the [examples](https://grafana.com/docs/grafana/latest/setup-grafana/configure-access/configure-authentication/generic-oauth/). For example, `role_attribute_path: contains(groups[*], 'Monitoring Admin') && 'Admin' || contains(groups[*], 'Monitoring') && 'Editor' || 'Viewer'` grants the “Admin” role to anyone in the “Monitoring Admin” group, the “Editor” role to anyone in the “Monitoring” group, and the “Viewer” role to any other signed-in user. 3. Log out and back in to update your role. ## Common problems [Section titled “Common problems”](#common-problems) * If you get locked out of your account before the OAuth setup is completed and need to reset the password, see [the Grafana CLI documentation](https://grafana.com/docs/grafana/latest/cli/#reset-admin-password). * If login fails because the callback URL is wrong and you are behind a reverse proxy, you might need to set `root_url` in `grafana.ini` so that it uses `https`, for example `https://grafana.example.com/`. * If everything is set according to the steps above and you still get `Login failed: Sign up is disabled`, you might need to set `oauth_allow_insecure_email_lookup=true` in the `[auth]` section of `grafana.ini`. # Grist > Sign in to the Grist spreadsheet tool with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Grist` and add the callback URL `https://grist.example.com/oauth2/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Grist [Section titled “Configure Grist”](#configure-grist) 1. In Grist (Docker, Docker Compose, etc.), set these environment variables: ```ini GRIST_OIDC_IDP_ISSUER="https://id.example.com" GRIST_OIDC_IDP_CLIENT_ID="" GRIST_OIDC_IDP_CLIENT_SECRET="" GRIST_OIDC_SP_HOST="https://grist.example.com" GRIST_OIDC_IDP_SCOPES="openid email profile" # Default GRIST_OIDC_IDP_END_SESSION_ENDPOINT="https://id.example.com/api/oidc/end-session" GRIST_OIDC_SP_IGNORE_EMAIL_VERIFIED=true # Needed if "Emails verified by default" is off (the default) in Administration → Application Configuration → Email in Pocket ID ``` 2. Make sure that the `GRIST_DEFAULT_EMAIL` environment variable is set to the same email address as your user profile in Pocket ID. 3. Start or restart Grist. # Harbor > Sign in to the Harbor container registry with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Harbor` and add the callback URL `https://harbor.example.com/c/oidc/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, set **Client Launch URL** to `https://harbor.example.com` and turn on **PKCE**, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Harbor [Section titled “Configure Harbor”](#configure-harbor) 1. Log in to [Harbor](https://goharbor.io/) as the admin user. 2. Open **Administration → Configuration** and select **Authentication**. 3. Fill in the fields: * **Auth Mode**: `OIDC` * **Primary Auth Mode**: checked if Pocket ID should be the primary authentication. * **OIDC Provider Name**: `Pocket ID` or something similar. * **OIDC Endpoint**: `https://id.example.com` * **OIDC Client ID**: the **Client ID** from Pocket ID. * **OIDC Client Secret**: the **Client secret** from Pocket ID. * **OIDC Group Filter**: leave blank. * **Group Claim Name**: `groups` * **OIDC Admin Group**: a Pocket ID group for administrators (e.g. `admin`), or leave blank. * **OIDC Scope**: `openid,offline_access,email,profile,groups` * **Verify Certificate**: checked. * **Automatic onboarding**: checked (or unchecked if you want users to change their username). * **OIDC Session Logout**: checked. * **Username Claim**: `email` 4. Save the settings. 5. Test the OIDC server. 6. Log out and sign in with Pocket ID to test it. ## Hints [Section titled “Hints”](#hints) * **Username Claim** can be any other claim (e.g. leave it empty for `name`, or set `sub`, `email`, …), depending on how your users should be named. * Use **OIDC Group Filter** if not all of your Pocket ID users should access the registry. * See [Configure OIDC Provider Authentication](https://goharbor.io/docs/2.13.0/administration/configure-authentication/oidc-auth/) for further help. ## Common problems [Section titled “Common problems”](#common-problems) * If you set the primary authentication mode to `OIDC` and can’t log in, avoid the redirect by using `https://harbor.example.com/account/sign-in` to log in as the local system administrator. * See the warning in the Harbor documentation: *You can change the authentication mode from database to OIDC only if no local users have been added to the database. If there is at least one user other than admin in the Harbor database, you cannot change the authentication mode.* # Headscale > Sign in to the Headscale VPN control server with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Headscale` and add the callback URL `https://headscale.example.com/oidc/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, turn on **PKCE**, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Headscale [Section titled “Configure Headscale”](#configure-headscale) Note Refer to the example [`config.yaml`](https://github.com/juanfont/headscale/blob/main/config-example.yaml) for full OIDC configuration options. Add the following to `config.yaml`: ```yaml oidc: issuer: 'https://id.example.com' client_id: '' client_secret: '' pkce: enabled: true method: S256 ``` ### Restrict access to certain groups [Section titled “Restrict access to certain groups”](#restrict-access-to-certain-groups) *(Optional)* To allow only specific groups, add the following under `oidc:`: ```yaml oidc: scope: ['openid', 'profile', 'email', 'groups'] allowed_groups: - # example: headscale ``` # Healthchecks > Sign in to the Healthchecks monitoring service with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [Healthchecks.io](https://healthchecks.io/docs/self_hosted_docker/) container self-hosted on Docker * [oauth2-proxy](https://github.com/oauth2-proxy/oauth2-proxy) reverse proxy container for authentication * Reverse proxy with SSL termination at the edge (HTTPS) ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Healthchecks` and add the callback URL `https://hc.example.com/oauth2/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, turn on **PKCE**, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure oauth2-proxy [Section titled “Configure oauth2-proxy”](#configure-oauth2-proxy) In the same `docker-compose.yml` you use for Healthchecks: 1. Add a new **oauth2-proxy** container under the `services:` section with the following config: ```yaml oauth2-proxy: image: quay.io/oauth2-proxy/oauth2-proxy restart: unless-stopped command: --config /oauth2-proxy.cfg volumes: - ./oauth2-proxy.cfg:/oauth2-proxy.cfg ports: - 1234:4180 ``` 2. Add the following to the Healthchecks `environment:` section: ```yaml - REMOTE_USER_HEADER=HTTP_X_FORWARDED_EMAIL ``` 3. Comment out the `ports:` section on Healthchecks, so that oauth2-proxy picks up the authentication request instead of Healthchecks directly. 4. Create a file beside `docker-compose.yml` called `oauth2-proxy.cfg` with the following config. Replace `` and `` with the **Client ID** and **Client secret** from Pocket ID: ```toml provider_display_name="Pocket ID" provider="oidc" oidc_issuer_url="https://id.example.com" client_id="" client_secret="" cookie_secret="xxx" # generate with: openssl rand -base64 32 | tr -- '+/' '-_' upstreams="http://healthchecks:8000" # internal port code_challenge_method="S256" # PKCE challenges plain or S256 skip_auth_routes = [".*/ping", ".*/api", ".*/badge"] reverse_proxy = true redirect_url="https://hc.example.com/oauth2/callback" scope = "openid email profile groups" cookie_expire="0" # seconds, 0 for session cookie_name="__Host-oauth2-proxy" # or __Secure-oauth2-proxy (less secure) cookie_secure="true" email_domains = ["*"] http_address="0.0.0.0:4180" insecure_oidc_allow_unverified_email = "true" ``` 5. Update your public-facing edge reverse proxy config (Caddy, Nginx, etc.) to forward `https://hc.example.com` to **port `1234`** (the external port for oauth2-proxy). 6. Restart the entire stack: ```bash docker compose down docker compose pull docker compose up -d ``` You can now sign in to Healthchecks with Pocket ID. ## Example full stack [Section titled “Example full stack”](#example-full-stack) ```yaml --- services: healthchecks: image: healthchecks/healthchecks:latest environment: - ALLOWED_HOSTS=hc.example.com - DB=sqlite - DB_NAME=/data/hc.sqlite - SECRET_KEY=${SECRET_KEY} - SITE_ROOT=https://hc.example.com - PING_EMAIL_DOMAIN=hc.example.com - REGISTRATION_OPEN=False - SITE_NAME=Healthchecks - RP_ID=hc.example.com - REMOTE_USER_HEADER=HTTP_X_FORWARDED_EMAIL volumes: - ./data:/data restart: unless-stopped # ports: # - 8000:8000 oauth2-proxy: image: quay.io/oauth2-proxy/oauth2-proxy restart: unless-stopped command: --config /oauth2-proxy.cfg volumes: - ./oauth2-proxy.cfg:/oauth2-proxy.cfg ports: - 1234:4180 ``` # Homarr > Sign in to the Homarr dashboard with Pocket ID. ## Create a group in Pocket ID [Section titled “Create a group in Pocket ID”](#create-a-group-in-pocket-id) 1. In Pocket ID, open **Administration → User Groups** and click **Add Group**. 2. Create a group called `homarr_admin` (or your preferred admin group name). ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Homarr` and add the callback URL `https://homarr.example.com/api/auth/callback/oidc`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, turn on **PKCE**, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Homarr [Section titled “Configure Homarr”](#configure-homarr) Add the following variables to your Homarr container `.env` file and restart: ```ini NEXTAUTH_SECRET= AUTH_PROVIDERS=oidc AUTH_OIDC_CLIENT_ID= AUTH_OIDC_CLIENT_SECRET= AUTH_OIDC_ISSUER=https://id.example.com AUTH_OIDC_CLIENT_NAME="Pocket ID" AUTH_OIDC_SCOPE_OVERWRITE=openid email profile groups AUTH_OIDC_GROUPS_ATTRIBUTE=groups AUTH_LOGOUT_REDIRECT_URL=https://id.example.com AUTH_OIDC_AUTO_LOGIN=true ``` ### Admin group [Section titled “Admin group”](#admin-group) During the initial setup of Homarr, you will be prompted to enter an admin group. Enter the name of the Pocket ID group that should receive admin rights (e.g., `homarr_admin`). Note You can optionally include `,credentials` in `AUTH_PROVIDERS` to keep local accounts as a fallback: ```ini AUTH_PROVIDERS=oidc,credentials ``` # HomeBox > Sign in to the HomeBox inventory system with Pocket ID. See the [HomeBox OIDC documentation](https://homebox.software/en/configure/oidc) for more configuration options. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `HomeBox` and add the callback URL `https://homebox.example.com/api/v1/users/login/oidc/callback/`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure HomeBox [Section titled “Configure HomeBox”](#configure-homebox) 1. Add the following environment variables to HomeBox: ```yaml - HBOX_OIDC_ENABLED=true - HBOX_OIDC_ISSUER_URL=https://id.example.com - HBOX_OIDC_CLIENT_ID= - HBOX_OIDC_CLIENT_SECRET= # Required if behind a reverse proxy so HomeBox detects HTTPS correctly - HBOX_OPTIONS_TRUST_PROXY=true # Optional: require verified email from Pocket ID # - HBOX_OIDC_VERIFY_EMAIL=true # Optional: auto-redirect to OIDC login (bypass local login screen) # - HBOX_OIDC_AUTO_REDIRECT=true # Optional: disable username/password login completely # - HBOX_OPTIONS_ALLOW_LOCAL_LOGIN=false ``` 2. Restart HomeBox. 3. You should now see a **Sign in with OIDC** button on the HomeBox login page. # Immich > Sign in to the Immich photo library with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Immich` and add the callback URLs: ```plaintext https://immich.example.com/auth/login https://immich.example.com/user-settings app.immich:///oauth-callback ``` 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Immich [Section titled “Configure Immich”](#configure-immich) 1. In Immich, open **Administration → Settings → Authentication Settings → OAuth**. 2. Enable **Login with OAuth**. 3. Fill in the fields: * **Issuer URL**: the **OIDC Discovery URL** from Pocket ID. * **Client ID**: the **Client ID** from Pocket ID. * **Client Secret**: the **Client secret** from Pocket ID. 4. *(Optional)* Change **Button Text** to `Login with Pocket ID`. 5. Save the settings and sign in with the OAuth button to test it. # InvenTree > Sign in to the InvenTree inventory management system with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [InvenTree](https://github.com/inventree/InvenTree) * Pocket ID on HTTPS, reachable at `https://` * InvenTree server on HTTPS, reachable at `https://` ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `InvenTree` and add the callback URL `https:///accounts//login/callback/`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, set **Client Launch URL** to `https://` and turn on **PKCE**, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. Choose a name for `` (e.g. `pocket-id`) and use the same value as `provider_id` in the configuration below. ## Configure InvenTree [Section titled “Configure InvenTree”](#configure-inventree) The following is the minimal configuration needed to set up Pocket ID OIDC with InvenTree. ### Option A: Configuration file (recommended) [Section titled “Option A: Configuration file (recommended)”](#option-a-configuration-file-recommended) 1. Add the following to your `config.yaml`, replacing values from Step 6: ```yaml social_backends: - 'allauth.socialaccount.providers.openid_connect' social_providers: openid_connect: APPS: - provider_id: pocket-id name: Pocket ID client_id: '' secret: '' settings: server_url: 'https://' fetch_userinfo: true oauth_pkce_enabled: true token_auth_method: client_secret_post ``` ### Option B: Environment variables [Section titled “Option B: Environment variables”](#option-b-environment-variables) 1. Add the following lines to your InvenTree `.env`, replacing the values from Step 7: ```bash INVENTREE_SOCIAL_BACKENDS=allauth.socialaccount.providers.openid_connect INVENTREE_SOCIAL_PROVIDERS={"openid_connect": {"SERVERS": [{"id": "pocket-id", "name": "Pocket ID", "server_url": "https://", "APP": {"client_id": "", "secret": ""}}]}} ``` 2. Save and restart the InvenTree docker-compose stack. ## Enable SSO in InvenTree [Section titled “Enable SSO in InvenTree”](#enable-sso-in-inventree) Once InvenTree is restarted, enable SSO via the admin UI: 1. Sign in as an admin. 2. Navigate to **System Settings → Authentication**. 3. Enable the following options: * **Enable SSO** * **Enable SSO registration** * **Auto-fill SSO users** > **Note:** If **Email Required** is enabled but SMTP is not configured, SSO login may fail during user registration. Add the following to use the console email backend as a workaround: > > ```bash > INVENTREE_EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend > INVENTREE_EMAIL_SENDER=inventree@inventree-tld.com > ``` # Jellyfin > Sign in to the Jellyfin media server with Pocket ID. Caution Due to the current limitations of the Jellyfin SSO plugin, this integration will only work in a browser. When tested, the Jellyfin app did not work and displayed an error, even when custom menu buttons were created. Current workflow: * Web browser: sign in using SSO * App (Android app, iOS app, smart TV app, Windows app): sign in via QuickConnect only To sign in to any app, click **QuickConnect**, then: 1. Open the web browser on your phone or PC and navigate to your Jellyfin. 2. Sign in using Pocket ID. 3. Accept the QuickConnect ID from the app. Note To view the original references and a full list of capabilities, visit the [Jellyfin SSO OpenID section](https://github.com/9p4/jellyfin-plugin-sso?tab=readme-ov-file#openid). ## Requirements [Section titled “Requirements”](#requirements) * [Jellyfin Server](https://jellyfin.org/downloads/server) * [Jellyfin SSO Plugin](https://github.com/9p4/jellyfin-plugin-sso) (archived by the owner on May 12, 2026) * HTTPS connection to your Jellyfin server Tip This guide covers two setups. Follow the steps marked with the emoji for the setup that suits you: * 😊 = Setup for normal users only (no distinction between users, no admins) * ⚡ = Setup for normal users and admins ## Create groups in Pocket ID [Section titled “Create groups in Pocket ID”](#create-groups-in-pocket-id) ⚡ only: 1. In Pocket ID, open **Administration → User Groups** and click **Add Group**. 2. Add the two groups `jellyfin_admins` and `jellyfin_users`. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Jellyfin` and add the callback URL `https://jellyfin.example.com/sso/OID/redirect/`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. Replace `` with the provider name you set in Jellyfin; this example uses `PocketID`. ⚡ On the **Access** tab, select the groups `jellyfin_admins` and `jellyfin_users`. ## Configure Jellyfin [Section titled “Configure Jellyfin”](#configure-jellyfin) 1. Visit the plugin page (**Administration Dashboard → My Plugins → SSO-Auth**). 2. Use the following values for the fields: * **Name of OID Provider**: `` (e.g. `PocketID`) * **OID Endpoint**: `https://id.example.com` * **OpenID Client ID**: the **Client ID** from Pocket ID * **OID Secret**: the **Client secret** from Pocket ID * **Enabled**: \[X] * **Enable Authorization by Plugin**: * 😊 -> \[ ] * ⚡ -> \[X] * **Enable All Folders**: \[ ] (Enable to publish all and new folders to every user) * **Enabled Folders**: Choose the folders/libraries which users will use * **Roles**: * 😊 -> \[ ] (if you have a group for Jellyfin users, use that group, e.g. `jellyfin_users`) * ⚡ -> add both groups, one per line: ```plaintext jellyfin_users jellyfin_admins ``` * **Admin Roles**: * 😊 -> \[ ] * ⚡ -> `jellyfin_admins` * **Enable Role-Based Folder Access**: \[ ] * **Enable Live TV RBAC**: \[ ] * **Live TV Roles**: \[ ] * **Live TV Management Roles**: \[ ] * **Enable Live TV Access By Default**: \[ ] * **Enable Live TV Management By Default**: \[ ] * **Role Claim**: `groups` * **Request Additional Scopes**: `groups` * **Set default Provider**: \[ ] * **Set default username claim**: `preferred_username` * **Set avatar url format**: `@{picture}` (Leave blank if you don’t want avatar sync) * **Disable OpenID HTTPS Discovery (Insecure)**: \[ ] * **Disable Pushed Authorization (Insecure)**: \[ ] * **Do Not Validate OpenID Endpoints (Insecure)**: \[ ] * **Do Not Validate OpenID Issuer Name (Insecure)**: \[ ] * **Scheme Override**: `https` * **Port Override**: \[ ] 3. Click **Save**. 4. Restart Jellyfin (**General → Restart**). ## Custom login button on the main page [Section titled “Custom login button on the main page”](#custom-login-button-on-the-main-page) *(Optional)* In the Jellyfin administration UI, under **Branding**, add the following code in the **Login disclaimer** block (replace ``, e.g. with `PocketID`): ```html
``` Then, add the following code in the **Custom CSS code** section: ```css a.raised.emby-button { padding: 0.9em 1em; color: inherit !important; } .disclaimerContainer { display: block; } ``` **Source**: [guide to create a login button on the login page](https://github.com/9p4/jellyfin-plugin-sso?tab=readme-ov-file#creating-a-login-button-on-the-main-page) ## Sign in to Jellyfin [Section titled “Sign in to Jellyfin”](#sign-in-to-jellyfin) Done! You have successfully set up SSO for your Jellyfin instance using Pocket ID. Note Sometimes there may be a brief delay when using the custom menu option. This is related to the Jellyfin plugin and not Pocket ID. If your users already have accounts, as long as their Pocket ID username matches their Jellyfin ID, they will be signed in automatically. Otherwise, a new user will be created with access to all of your folders. You can change this in your configuration as desired. This setup will only work if sign-in is performed using the `https://jellyfin.example.com/sso/OID/start/` URL. This URL initiates the SSO plugin and applies all the configurations we completed above. *** Written for Jellyfin v10.11.2 and SSO-Auth-Plugin v4.0.0.2 # Karakeep > Sign in to the Karakeep bookmark manager with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Karakeep` and add the callback URL `https://karakeep.example.com/api/auth/callback/custom`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Karakeep [Section titled “Configure Karakeep”](#configure-karakeep) 1. Open the `.env` file of your Karakeep compose setup and add these lines: ```ini OAUTH_WELLKNOWN_URL=https://id.example.com/.well-known/openid-configuration OAUTH_CLIENT_SECRET= OAUTH_CLIENT_ID= OAUTH_PROVIDER_NAME="Pocket ID" NEXTAUTH_URL=https://karakeep.example.com ``` 2. *(Optional)* To disable password authentication and link your existing Karakeep account with your Pocket ID identity, also add: ```ini DISABLE_PASSWORD_AUTH=true OAUTH_ALLOW_DANGEROUS_EMAIL_ACCOUNT_LINKING=true ``` # Kasm Workspaces > Sign in to Kasm Workspaces with Pocket ID. ## Get the redirect URL from Kasm [Section titled “Get the redirect URL from Kasm”](#get-the-redirect-url-from-kasm) 1. In Kasm, sign in with an administrator account. 2. From the navigation pane on the left, select **Access Management → Authentication → OpenID**. 3. Click the **Add Config** button on the right. Scroll to the bottom of the page and copy the **Redirect URL**; this will be the callback URL in Pocket ID. 4. Open Pocket ID in a new tab and continue below. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Kasm Workspaces` and add the callback URL `https://kasm.example.com/api/oidc_callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL**, the **Token URL** and the **Userinfo URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. Use the **Redirect URL** you copied from Kasm as the callback URL. Note Don’t turn on **PKCE**, as Kasm doesn’t support it. ## Configure Kasm [Section titled “Configure Kasm”](#configure-kasm) 1. Back in the Kasm admin view, fill out the fields as follows: * **Display name**: the text a Kasm user will see when signing in (example: `Click here to authenticate with Pocket ID`, or similar). * **Auto login**: *(Optional)* Enable this to bypass the Kasm local login and go straight to Pocket ID. This can be enabled *after* setup is complete. * **Client ID**: the **Client ID** from Pocket ID. * **Client Secret**: the **Client secret** from Pocket ID. * **Authorization URL**: the **Authorization URL** from Pocket ID. * **Token URL**: the **Token URL** from Pocket ID. * **User Info URL**: the **Userinfo URL** from Pocket ID. * **Scope**: The following values can be entered: \[`openid, email, profile, groups`]. These values can be found by opening the **OIDC Discovery URL** in a web browser and looking for the `scopes_supported` string. * **Username attribute**: `preferred_username` * **Groups attribute**: `groups` * **Redirect URL**: This value is pre-populated and doesn’t need to be changed. * **OpenID Connect Issuer**: This URL is optional and is simply the base URL where Pocket ID is accessed (example: `https://id.example.com`). * **Logout with OIDC provider**: This is configured in conjunction with the **OpenID Connect Issuer** above. If configured, a user who signs out of Kasm is also signed out of Pocket ID for additional security. 2. Save the configuration and sign in to Kasm in a private browser window to test it. You should be able to click the Pocket ID button to sign in. If auto login was enabled, Kasm redirects to Pocket ID immediately, skipping the Kasm local login. Note If you need to sign in to Kasm using local accounts (for instance, admin access), click **Cancel** in Pocket ID before selecting your passkey. If auto login is enabled, this has to be done quickly before Pocket ID redirects to Kasm. # Kavita > Sign in to the Kavita reading server with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Kavita` and add the callback URL `https://kavita.example.com/signin-oidc`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, add `https://kavita.example.com/signout-callback-oidc` to **Logout Callback URLs**, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Kavita [Section titled “Configure Kavita”](#configure-kavita) 1. In Kavita, go to **Settings → Server → OpenID Connect**. 2. Enter your OIDC provider details: * **Authority**: `https://id.example.com` (no trailing slash) * **Client ID**: the **Client ID** from Pocket ID * **Client Secret**: the **Client secret** from Pocket ID * *(Optional)* **Provider name**: Change to `Pocket ID` if you wish. 3. Save and restart the Kavita server for the settings to take effect. If **Require verified emails** is enabled in Kavita, turn on **Emails verified by default** in Pocket ID under **Administration → Application Configuration → Email** to ensure users can sign in. 4. Sign in with the newly added button to test it. ## Sync user permissions [Section titled “Sync user permissions”](#sync-user-permissions) Kavita allows for configuration of user access via synced roles as a custom claim. 1. In Pocket ID, open the user (**Administration → Users**) or the group (**Administration → User Groups**) that should have access to Kavita. 2. Under **Custom Claims**, add a key-value pair: * Use a key name that will be unique to Kavita, like `kavita-roles`. * Set the value to the roles you wish to give that user. For multiple roles, format it like this: `[ "Login", "Download", "library-Comics" ]` * `Login` is required to fully sign in to Kavita. Other roles can be found in Kavita’s [documentation](https://wiki.kavitareader.com/guides/admin-settings/users/#roles). * Access to libraries must be granted with `library-`. 3. Save the custom claim in Pocket ID, then sign in to Kavita separately with an admin account. 4. In Kavita, go to **Settings → Server → OpenID Connect**. 5. Enable **Sync user settings with OIDC roles**. 6. Scroll down to **Advanced Settings** and change the **Roles claim** to the key name you set earlier (`kavita-roles` for example). 7. Scroll up and click **Save**, then restart the Kavita server. 8. Sign in to Kavita with a user that has the custom claims applied. It should map the roles on sign-in. Note Role changes in the claim will not take effect until the user signs in again. For more information on OIDC settings in Kavita, refer to their [documentation](https://wiki.kavitareader.com/guides/admin-settings/open-id-connect/). # Komodo > Sign in to Komodo with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Komodo` and add the callback URL `https://komodo.example.com/auth/oidc/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Komodo [Section titled “Configure Komodo”](#configure-komodo) **This example uses the docker-compose deployment type of Komodo.** See the [official docs](https://komo.do/docs/intro) for more information. Add the following lines to your Komodo `.env` file, replacing the values with the ones you copied above: ```ini KOMODO_OIDC_ENABLED=true KOMODO_OIDC_PROVIDER=https://id.example.com KOMODO_OIDC_CLIENT_ID= KOMODO_OIDC_CLIENT_SECRET= ## Make usernames the full email. KOMODO_OIDC_USE_FULL_EMAIL=true ``` Save and redeploy Komodo, and you should be able to sign in using OIDC with Pocket ID. # LinkAce > Sign in to the LinkAce bookmark archive with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `LinkAce`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure LinkAce [Section titled “Configure LinkAce”](#configure-linkace) Set the following environment variables: ```yaml SSO_ENABLED: true SSO_OIDC_ENABLED: true SSO_OIDC_BASE_URL: https://id.example.com SSO_OIDC_CLIENT_ID: SSO_OIDC_CLIENT_SECRET: SSO_OIDC_SCOPES: "openid profile email" ``` # Linkding > Sign in to the Linkding bookmark manager with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Linkding` and add the callback URL `https://linkding.example.com/oidc/callback/`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Linkding [Section titled “Configure Linkding”](#configure-linkding) This example assumes you are using a docker-compose deployment for Linkding. For more details, see the [Linkding documentation](https://linkding.link/installation) or, more specifically, [the OIDC section](https://linkding.link/options/#ld_enable_oidc). 1. Add the following environment variables to your Linkding `.env` file. Replace `` and `` with the **Client ID** and **Client secret** from Pocket ID. The endpoints are listed in Pocket ID under **Show more details** (**Authorization URL**, **Token URL**, **Userinfo URL** and **Certificate URL**). ```ini # Enable OIDC in Linkding LD_ENABLE_OIDC=True # Client credentials from Pocket ID OIDC_RP_CLIENT_ID= OIDC_RP_CLIENT_SECRET= # OIDC endpoints OIDC_OP_AUTHORIZATION_ENDPOINT=https://id.example.com/authorize OIDC_OP_TOKEN_ENDPOINT=https://id.example.com/api/oidc/token OIDC_OP_USER_ENDPOINT=https://id.example.com/api/oidc/userinfo OIDC_OP_JWKS_ENDPOINT=https://id.example.com/.well-known/jwks.json # Use PKCE if required (adjust based on your setup, True by default) OIDC_USE_PKCE=False # Verify SSL certificate (set to False if using self-signed certificates) OIDC_VERIFY_SSL=True # Optional: Customize the username claim (defaults to email if not set) # OIDC_USERNAME_CLAIM=preferred_username ``` 2. Save the changes to your `.env` file and redeploy your Linkding instance using docker-compose. Once redeployed, you should be able to sign in using OIDC with Pocket ID. # LubeLogger > Sign in to the LubeLogger vehicle maintenance tracker with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [LubeLogger](https://lubelogger.com/) * HTTPS connection to your LubeLogger server ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `LubeLogger` and add the callback URL `https://lubelogger.example.com/Login/RemoteAuth`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL**, the **Token URL**, the **Userinfo URL**, the **Logout URL** and the **Certificate URL**. The client secret is only shown once. 4. On the client’s **General** tab, turn on **PKCE**, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure LubeLogger [Section titled “Configure LubeLogger”](#configure-lubelogger) 1. Open LubeLogger and navigate to **User Icon → Configure → Acknowledge and Continue → Next → Next → Next → Single Sign On**. 2. Enter the following values from Pocket ID. Leave all others empty or at their defaults. | LubeLogger | Pocket ID value | | ------------------ | --------------------- | | OIDC Provider | `Pocket ID` | | OIDC Client ID | **Client ID** | | OIDC Client Secret | **Client secret** | | OIDC Auth URL | **Authorization URL** | | OIDC Token URL | **Token URL** | | OIDC UserInfo URL | **Userinfo URL** | | OIDC JWKS URL | **Certificate URL** | | OIDC Logout URL | **Logout URL** | | OIDC USE PKCE | `True` | 3. Click **Next**. 4. Enable OIDC for Root User. 5. Enter the Root User Email Address. 6. Click **Save**. 7. Return to **Garage** and sign out to test the connection. After signing out, you should see a **Login via Pocket ID** button. # Mealie > Sign in to the Mealie recipe manager with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Mealie` and add the callback URL `https://mealie.example.com/login`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Mealie [Section titled “Configure Mealie”](#configure-mealie) Add the following to your Docker `compose.yaml` or `.env` file for Mealie. Example directly in `compose.yaml`: ```yaml environment: ALLOW_SIGNUP: 'true' # LOG_LEVEL: "DEBUG" # DB_ENGINE: sqlite # Optional: 'sqlite', 'postgres' OIDC_AUTH_ENABLED: True OIDC_SIGNUP_ENABLED: True OIDC_CONFIGURATION_URL: https://id.example.com/.well-known/openid-configuration OIDC_CLIENT_ID: OIDC_CLIENT_SECRET: ``` Example using an `.env` file: ```ini OIDC_AUTH_ENABLED=true OIDC_SIGNUP_ENABLED=true OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= OIDC_PROVIDER_NAME="Pocket ID" OIDC_CONFIGURATION_URL=https://id.example.com/.well-known/openid-configuration # Optionally, uncomment the following: # ALLOW_SIGNUP=false # Disables Mealie's public/local account registration. Users cannot create accounts through Mealie's standard signup form. # OIDC_SIGNUP_ENABLED=true # Allows Mealie to create an account automatically when an authorized Pocket ID user signs in for the first time. # ALLOW_PASSWORD_LOGIN=false # Disables Mealie's local username and password login form. Authentication must occur through Pocket ID. # OIDC_AUTO_REDIRECT=true # Bypasses Mealie's login selection page and redirect visitors directly to Pocket ID for authentication. ``` If you are using an `.env` file, reference it in your `compose.yaml` under the `mealie` service: ```yaml env_file: - .env ``` # Memos > Sign in to the Memos note-taking app with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Memos` and add the callback URL `https://memos.example.com/auth/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL**, the **Token URL** and the **Userinfo URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Memos [Section titled “Configure Memos”](#configure-memos) 1. Sign in to Memos as an admin. 2. Go to **Settings → SSO → Create**. 3. Set **Template** to `Custom`. 4. Enter the **Client ID** from Pocket ID into the **Client ID** field. 5. Enter the **Client secret** from Pocket ID into the **Client secret** field. 6. Enter the **Authorization URL** from Pocket ID into the **Authorization endpoint** field. 7. Enter the **Token URL** from Pocket ID into the **Token endpoint** field. 8. Enter the **Userinfo URL** from Pocket ID into the **User endpoint** field. 9. Set **Scopes** to `openid email profile`. 10. Set **Identifier** to `preferred_username`. 11. Set **Display Name** to `name`. 12. Set **Email** to `email`. 13. Save the settings and sign in with Pocket ID to test it. # MeshCentral > Sign in to the MeshCentral device manager with Pocket ID. Replace `meshcentral.example.com` with the domain of your MeshCentral instance and `id.example.com` with the domain of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `MeshCentral`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure MeshCentral [Section titled “Configure MeshCentral”](#configure-meshcentral) Update the `authStrategies` object in your `config.json` to match the following, with the **Client ID** and the **Client secret** from Pocket ID: ```json "domains": { "": { "authStrategies": { "oidc": { "client": { "client_id": "", "client_secret": "", "redirect_uri": "https://meshcentral.example.com/auth-oidc-callback" }, "issuer": { "issuer": "https://id.example.com" } } } } } ``` # Miniflux > Sign in to the Miniflux RSS reader with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Miniflux` and add the callback URL `https://miniflux.example.com/oauth2/oidc/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Miniflux [Section titled “Configure Miniflux”](#configure-miniflux) 1. Set the following environment variables in your Miniflux instance: ```ini OAUTH2_PROVIDER=oidc OAUTH2_CLIENT_ID= OAUTH2_CLIENT_SECRET= OAUTH2_REDIRECT_URL=https://miniflux.example.com/oauth2/oidc/callback OAUTH2_OIDC_DISCOVERY_ENDPOINT=https://id.example.com # no trailing slashes or ".well-known/openid-configuration" OAUTH2_OIDC_PROVIDER_NAME=PocketID OAUTH2_USER_CREATION=1 # optional, if you want new users to be created automatically DISABLE_LOCAL_AUTH=1 # optional, if you want to disable local authentication ``` 2. Restart Miniflux and sign in with Pocket ID to test it. # MinIO > Sign in to the MinIO object storage console with Pocket ID. ## Create groups in Pocket ID [Section titled “Create groups in Pocket ID”](#create-groups-in-pocket-id) 1. In Pocket ID, open **Administration → User Groups** and click **Add Group**. 2. Create a group with the **Name** `consoleAdmin` (case-sensitive). 3. Add your user to the `consoleAdmin` group to sign in to MinIO as an administrator. You can also add groups for the other built-in policies; see the [MinIO documentation](https://min.io/docs/minio/linux/administration/identity-access-management/policy-based-access-control.html#built-in-policies) for details. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `MinIO` and add the callback URL `https://minio-console.example.com/oauth_callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure MinIO [Section titled “Configure MinIO”](#configure-minio) 1. Sign in to MinIO with an admin (or root) account. 2. Under **Administrator**, select **Identity**, then **OpenID**. 3. Click **Create Configuration** and fill in the fields: * **Config URL**: `https://id.example.com/.well-known/openid-configuration` * **Client ID**: the **Client ID** from Pocket ID. * **Client Secret**: the **Client secret** from Pocket ID. * **Claim Name**: `groups` * **Display Name**: `Pocket ID` (or anything you want) * **Scopes**: `openid,profile,email,groups` * **Redirect URI**: `https://minio-console.example.com/oauth_callback` ## Notes [Section titled “Notes”](#notes) * You need to enter the client secret every time you edit the OpenID configuration. Instead of managing the secret, you can add a new one on the client’s **Credentials** tab in Pocket ID with **Add client secret** and enter that. * If you use `MINIO_BROWSER_REDIRECT_URL=https://minio.example.com/minio-console/` in your MinIO configuration, use `https://minio.example.com/minio-console/oauth_callback` as the callback URL in Pocket ID and as the **Redirect URI** in the MinIO OpenID configuration. # NetBird > Sign in to NetBird (through ZITADEL) with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * NetBird self-hosted, configured with HTTPS * Pocket ID, configured with HTTPS ## Overview [Section titled “Overview”](#overview) The NetBird self-hosted [quick start guide](https://docs.netbird.io/selfhosted/selfhosted-quickstart) configures NetBird with the default ZITADEL identity provider (IdP). This guide shows how to configure **pass-through OpenID authentication** via ZITADEL, back to Pocket ID. Changing the NetBird IdP *directly* from ZITADEL to Pocket ID is **not** covered in this guide because of its complexity. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `NetBird` and add the callback URLs: ```plaintext https://netbird.example.com/ui/login/login/externalidp/callback https://netbird.example.com/idps/callback ``` 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. The first callback URL is for ZITADEL Login V1 and the second for Login V2, so you only need the one your ZITADEL uses. ## Connect ZITADEL to Pocket ID [Section titled “Connect ZITADEL to Pocket ID”](#connect-zitadel-to-pocket-id) Connect the ZITADEL IdP to Pocket ID for pass-through: 1. Confirm that the **NetBird** management console loads at `https://netbird.example.com`. 2. Sign in to the **ZITADEL** management console at `https://netbird.example.com/ui/console`. 3. Open **Organization → Login and Access → Modify**. 4. Open **Login and Access → Identity Providers**. 5. Under **Add Provider**, click **Generic OIDC**. 6. Confirm that the **ZITADEL Callback URL** shown by the provider matches the callback URL in Pocket ID. 7. Set the **Name** to `Pocket ID` or anything you want. 8. Set the **Issuer** to your Pocket ID URL, for example `https://id.example.com`. 9. Set the **Client ID** to the **Client ID** from Pocket ID. 10. Set the **Client Secret** to the **Client secret** from Pocket ID. 11. Expand the **Optional** settings. 12. Add `groups` to the **Scopes** list. 13. Enable **Automatic creation**. 14. *(Optional)* Enable **Automatic update**. 15. *(Optional)* Enable **Account creation allowed (manually)**. 16. *(Optional)* Enable **Account linking allowed (manually)**. 17. *(Optional)* Set the identity prompt dropdown to **Check for existing email** or your choice. 18. Click **Save**. 19. Click **Activate**. 20. Sign in to ZITADEL with Pocket ID to test it. ## Auto-approve NetBird users [Section titled “Auto-approve NetBird users”](#auto-approve-netbird-users) We recommend auto-approving NetBird users (via IdP from ZITADEL) to avoid manual work: 1. Sign in to **NetBird** with an existing admin account. 2. Open **Settings → Authentication**. 3. Disable **User Approval Required**. 4. Click **Save Changes**. ## Set ZITADEL login preferences [Section titled “Set ZITADEL login preferences”](#set-zitadel-login-preferences) *(Optional)* Return to the ZITADEL management console and set your preferences: 1. Open **Organization → Login and Access → Modify** again. 2. In the **Login Behaviour and Security** section, scroll down. 3. Under **Login Form**: * Disable **Username and Password allowed**. * Disable **User Registration allowed**. * Enable **External Login allowed**. * Enable **Password Reset hidden**. # NetBox > Sign in to the NetBox IPAM tool with Pocket ID. **This guide doesn’t currently show how to map groups in NetBox from OIDC claims.** Replace `netbox.example.com` with the domain of your NetBox instance and `id.example.com` with the domain of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `NetBox` and add the callback URL `https://netbox.example.com/oauth/complete/oidc/`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure NetBox [Section titled “Configure NetBox”](#configure-netbox) This guide assumes you use the Git-based installation of NetBox. 1. On your NetBox server, open `/opt/netbox/netbox/netbox`. 2. Add the following to your `configuration.py` file, with the **Client ID** and the **Client secret** from Pocket ID: ```python # Remote authentication support REMOTE_AUTH_ENABLED = True REMOTE_AUTH_BACKEND = 'social_core.backends.open_id_connect.OpenIdConnectAuth' REMOTE_AUTH_HEADER = 'HTTP_REMOTE_USER' REMOTE_AUTH_USER_FIRST_NAME = 'HTTP_REMOTE_USER_FIRST_NAME' REMOTE_AUTH_USER_LAST_NAME = 'HTTP_REMOTE_USER_LAST_NAME' REMOTE_AUTH_USER_EMAIL = 'HTTP_REMOTE_USER_EMAIL' REMOTE_AUTH_AUTO_CREATE_USER = True REMOTE_AUTH_DEFAULT_GROUPS = [] REMOTE_AUTH_DEFAULT_PERMISSIONS = {} SOCIAL_AUTH_OIDC_ENDPOINT = 'https://id.example.com' SOCIAL_AUTH_OIDC_KEY = '' SOCIAL_AUTH_OIDC_SECRET = '' LOGOUT_REDIRECT_URL = 'https://netbox.example.com' ``` 3. Save the file and restart NetBox: `sudo systemctl restart netbox netbox-rq`. # Nextcloud > Sign in to Nextcloud with Pocket ID. Nextcloud doesn’t come with OIDC/SSO out of the box, so you need to install a Nextcloud app for it. There are two main options: `nextcloud/user_oidc` and `pulsejet/nextcloud-oidc-login`. This guide uses **`nextcloud/user_oidc`**, because it’s maintained by Nextcloud and is expected to be supported longer. Replace `nextcloud.example.com` with the domain of your Nextcloud instance and `id.example.com` with the domain of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Nextcloud`, keep **Confidential Client** as the client type and add the callback URL `https://nextcloud.example.com/apps/user_oidc/code`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. Also copy the **Logout URL**, which is under **Show more details**. The client secret is only shown once. 4. On the client’s **General** tab, set **Back-Channel Logout URL** to the address the `user_oidc` app gives you. Usually it’s `https://nextcloud.example.com/apps/user_oidc/backchannel-logout/PocketID`, where `PocketID` is the identifier you give the provider in Nextcloud. Consider turning on **PKCE**, then save. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Nextcloud [Section titled “Configure Nextcloud”](#configure-nextcloud) 1. Sign in to Nextcloud with your admin account. 2. In the upper right corner, click your profile picture and select **Apps**. 3. Under **Integration**, select **OpenID Connect user backend** and install it. 4. After installing, go to **Administration settings → OpenID Connect**. 5. Click **+** and fill in the information as follows: 1. **Identifier**: `PocketID` (suggestion only) 2. **Client ID**: the **Client ID** from Pocket ID. 3. **Client secret**: the **Client secret** from Pocket ID. 4. **Discovery endpoint**: the **OIDC Discovery URL** from Pocket ID. 5. **Custom end session endpoint**: the **Logout URL** from Pocket ID. 6. **Scope**: `openid email profile groups` 7. By default, Nextcloud creates a new user when someone signs in with Pocket ID. If you want to sign in with an existing Nextcloud user, you need to tell Nextcloud how to match Pocket ID users with Nextcloud users. You can either: * Match accounts using a custom claim: set **User ID mapping** to `nextcloud_username`. Then, for each user in Pocket ID, add a custom claim under **Custom Claims** on the user’s page, with the key `nextcloud_username` and the Nextcloud account name to sign in to as the value. * If you have turned off **Enable Self-Account Editing** in the Pocket ID configuration, match accounts using the Pocket ID username directly: set **User ID mapping** to `preferred_username`. If **Enable Self-Account Editing** is on, Pocket ID users can change their own username and therefore choose the Nextcloud account they sign in to. 8. *(Optional)* Open **Extra-Attribute-Mapping** and set **Avatar-Mapping** to `picture`. This downloads the profile picture from Pocket ID. 9. *(Optional)* Check **Use group provisioning** if you want Pocket ID groups to be replicated on Nextcloud. 10. *(Optional)* If you use groups, you can whitelist them with **Group-Whitelist-Regex**, for example `^(nextcloud_(admins|users))$`. This regex matches both the `nextcloud_admins` and `nextcloud_users` groups. If you also enable the next option, **User Login only matching Whitelist-Regex**, only users in these groups have access. 11. Check **Use unique user ID** and uncheck **Send ID token hint on logout**. 6. After creating the provider, make sure the **Backchannel Logout URL** and **Redirect URI** shown by Nextcloud match the **Back-Channel Logout URL** and the callback URL in Pocket ID. ## Sign in on the Nextcloud mobile app [Section titled “Sign in on the Nextcloud mobile app”](#sign-in-on-the-nextcloud-mobile-app) The Nextcloud app for iOS doesn’t accept passkey input, which creates a small barrier when using Pocket ID. If you didn’t disable the regular login, you can use your Nextcloud username and password to sign in. If you disabled the regular login, create a **Login Code** on your Pocket ID dashboard (`id.example.com`). Then open the Nextcloud app and add your Nextcloud URL (`nextcloud.example.com`). When the Pocket ID login appears, select **Don’t have access to your passkey?**, select **Login Code** and enter the code you created. ## Disable the Nextcloud login form [Section titled “Disable the Nextcloud login form”](#disable-the-nextcloud-login-form) You can disable the built-in login form in two ways, with slightly different outcomes: 1. Hide the login form: in the Nextcloud `config.php`, set `'hide_login_form' => true`. Nextcloud still shows its login page at `nextcloud.example.com`, but it says “The Nextcloud login form is disabled.” and shows a `Login with PocketID` button instead. The login form is only hidden and can still be accessed by appending `login?direct=1` to the URL: `nextcloud.example.com/login?direct=1`. ![Nextcloud login page with the login form disabled](https://github.com/user-attachments/assets/a34b5ea2-bc86-4d10-8a0e-6c253329235e) 2. Remove the login form: run a command with the Nextcloud CLI inside the container. Since there are many containers and platforms, make sure to use the right form for your container and platform. 1. Run `occ config:app:set user_oidc allow_multiple_user_backends --value=0`. 2. The built-in login form is no longer available at `nextcloud.example.com`, and you’re automatically redirected to sign in with Pocket ID. 3. This only works if there is a single OIDC provider and no other login methods. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If you get the error “Could not update the provider: The discovery endpoint is not reachable.” when creating the OIDC provider in Nextcloud: 1. Check the Nextcloud server log for a detailed error message 2. If you are on a local network, you may need to set/adjust the following option in your `config.php` file: ```php 'allow_local_remote_servers' => true ``` Restart the Nextcloud server and try setting up OIDC again. If you can’t sign in to Nextcloud: 1. Using the Nextcloud CLI, reactivate the login form: `occ config:app:set user_oidc allow_multiple_user_backends --value=1`. 2. Remove the current OIDC configuration with `occ user_oidc:provider:delete PocketID`. Replace `PocketID` with the identifier you used, or the one listed by `occ user_oidc:provider`. 3. Create a new OIDC connection with the command below. Make sure to adjust it as appropriate. 1. After the command is run and you can login back to Nextcloud, make sure to adjust the `Scope`and 2. Run: ```bash occ user_oidc:provider PocketID \ --clientid="" \ --clientsecret="" \ --discoveryuri="https://id.example.com/.well-known/openid-configuration" \ --mapping-uid="preferred_username" \ --unique-uid=1 \ --send-id-token-hint=0 ``` Replace `PocketID`, ``, `` and the discovery URL with your identifier and the **Client ID**, **Client secret** and **OIDC Discovery URL** from Pocket ID. # nextExplorer > Sign in to the nextExplorer file manager with Pocket ID. Replace `id.example.com` with the domain of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `nextExplorer`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure nextExplorer [Section titled “Configure nextExplorer”](#configure-nextexplorer) 1. Set the following environment variables: ```yaml OIDC_ENABLED: true OIDC_ISSUER: https://id.example.com OIDC_CLIENT_ID: OIDC_CLIENT_SECRET: OIDC_SCOPES: "openid profile email" OIDC_ADMIN_GROUPS: OIDC_REQUIRE_EMAIL_VERIFIED: true/false OIDC_AUTO_CREATE_USERS: true/false AUTH_MODE: oidc/local/both/disabled ``` `AUTH_MODE` sets the authentication flow: * `oidc` allows OIDC only and disables local passwords. * `local` allows username and password only and hides OIDC. * `both` allows a choice between OIDC and local login. * `disabled` turns off the login page entirely. 2. Start the instance and sign in with Pocket ID to test it. See the [nextExplorer documentation](https://explorer.nxz.ai/integrations/oidc.html) for more details. # Node-RED > Sign in to the Node-RED editor with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Node-RED` and add the callback URL `https://nodered.example.com/auth/strategy/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL**, the **Token URL** and the **Userinfo URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Node-RED [Section titled “Configure Node-RED”](#configure-node-red) 1. Make sure the following Passport strategy package is installed: ```bash npm install passport-openidconnect ``` 2. Replace the `adminAuth` section in `settings.js` (adjust it to your requirements): ```js adminAuth: { type: 'strategy', strategy: { name: 'openidconnect', label: 'Sign in with Pocket ID', icon: 'fa-openid', strategy: require('passport-openidconnect').Strategy, options: { issuer: 'https://id.example.com', authorizationURL: 'https://id.example.com/authorize', tokenURL: 'https://id.example.com/api/oidc/token', userInfoURL: 'https://id.example.com/api/oidc/userinfo', clientID: '', clientSecret: '', callbackURL: 'https://nodered.example.com/auth/strategy/callback', scope: ['openid', 'email', 'profile', 'groups'], proxy: true, verify: function(issuer, profile, done) { done(null, profile) } } }, users: function(user) { return Promise.resolve({ username: user, permissions: "*" }); } }, ``` 3. Restart the container after editing `settings.js`. # oCIS > Sign in to ownCloud Infinite Scale (oCIS) with Pocket ID. [ownCloud Infinite Scale (oCIS)](https://owncloud.dev/ocis/) is the new file sync and share platform that will be the foundation of your data management platform. Replace `ocis.example.com` with the domain of your oCIS server and `id.example.com` with the domain of your Pocket ID server. Note This guide lists only the settings that you need to change from their default values. Any changes other than those explicitly mentioned in this guide could cause issues accessing your application. ## Create groups in Pocket ID [Section titled “Create groups in Pocket ID”](#create-groups-in-pocket-id) 1. In Pocket ID, open **Administration → User Groups** and click **Add Group** for each of these four groups: * **Friendly Name** `ocis admin users group`, **Name** `ocisAdmin` * **Friendly Name** `ocis space admin user group`, **Name** `ocisSpaceAdmin` * **Friendly Name** `ocis user group`, **Name** `ocisUser` * **Friendly Name** `ocis guest group`, **Name** `ocisGuest` 2. On each group’s page, add a claim under **Custom Claims** with the key `roles` and the group’s name as the value, and save: * `ocisAdmin` group: `roles` = `ocisAdmin` * `ocisSpaceAdmin` group: `roles` = `ocisSpaceAdmin` * `ocisUser` group: `roles` = `ocisUser` * `ocisGuest` group: `roles` = `ocisGuest` 3. Add users to the groups: admin users to `ocisAdmin`, space admin users to `ocisSpaceAdmin`, standard users to `ocisUser` and guests to `ocisGuest`. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `oCIS`, choose **Public Client** as the client type and add the callback URLs: ```plaintext https://ocis.example.com/ https://ocis.example.com/oidc-callback.html https://ocis.example.com/oidc-silent-redirect.html ``` 3. Click **Create** and copy the **Client ID**. 4. On the client’s **Access** tab, select `ocisAdmin`, `ocisSpaceAdmin`, `ocisUser` and `ocisGuest` under **Allowed User Groups**. ## Configure oCIS [Section titled “Configure oCIS”](#configure-ocis) ### Environment variables [Section titled “Environment variables”](#environment-variables) Set the following environment variables, with the **Client ID** from Pocket ID as `WEB_OIDC_CLIENT_ID`: ```ini OCIS_URL=https://ocis.example.com PROXY_AUTOPROVISION_ACCOUNTS=true PROXY_ROLE_ASSIGNMENT_DRIVER=oidc OCIS_OIDC_ISSUER=https://id.example.com PROXY_OIDC_REWRITE_WELLKNOWN=true WEB_OIDC_CLIENT_ID= PROXY_USER_OIDC_CLAIM=preferred_username OCIS_EXCLUDE_RUN_SERVICES=idp PROXY_CSP_CONFIG_FILE_LOCATION=/etc/ocis/csp.yaml ``` ### Content Security Policy [Section titled “Content Security Policy”](#content-security-policy) For an example `csp.yaml`, see the [oCIS Keycloak example](https://github.com/owncloud/ocis/blob/master/deployments/examples/ocis_keycloak/config/ocis/csp.yaml). Change the Pocket ID URL under `connect-src` (line 9 below) to your Pocket ID URL, and mount the file at `/etc/ocis/csp.yaml` in your Podman or Docker settings. ```yaml directives: child-src: - '''self''' connect-src: - '''self''' - 'blob:' - 'https://raw.githubusercontent.com/owncloud/awesome-ocis/' # In contrary to bash and docker the default is given after the | character - 'https://id.example.com/' default-src: - '''none''' font-src: - '''self''' frame-ancestors: - '''none''' frame-src: - '''self''' - 'blob:' - 'https://embed.diagrams.net/' img-src: - '''self''' - 'data:' - 'blob:' - 'https://raw.githubusercontent.com/owncloud/awesome-ocis/' manifest-src: - '''self''' media-src: - '''self''' object-src: - '''self''' - 'blob:' script-src: - '''self''' - '''unsafe-inline''' style-src: - '''self''' - '''unsafe-inline''' ``` ## Create the desktop and mobile clients [Section titled “Create the desktop and mobile clients”](#create-the-desktop-and-mobile-clients) The client IDs and secrets are hardcoded in the ownCloud desktop and mobile clients. You can find these values in the [ownCloud documentation](https://doc.owncloud.com/server/10.15/admin_manual/configuration/user/oidc/oidc.html#client-ids-secrets-and-redirect-uris). Pocket ID doesn’t support hardcoded client secrets. Because ownCloud implements the optional PKCE extension, you can create the desktop and mobile clients as public clients instead. For each client below: 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter the name and the callback URL from the list, and choose **Public Client** as the client type. 3. Click **Set custom client ID** and enter the client ID from the list. 4. Click **Create**. 5. On the client’s **Access** tab, select `ocisAdmin`, `ocisSpaceAdmin`, `ocisUser` and `ocisGuest` under **Allowed User Groups**. The clients: * **Desktop client** * Name: `ownCloud Desktop Client` * Callback URL: `http://127.0.0.1:*` * Client ID: `xdXOt13JKxym1B1QcEncf2XDkLAexMBFwiT9j6EfhhHFJhs2KM9jbjTmf8JBXE69` * **iOS client** * Name: `ownCloud iOS Client` * Callback URL: `oc://ios.owncloud.com` * Client ID: `mxd5OQDk6es5LzOzRvidJNfXLUZS2oN3oUFeXPP8LpPrhx3UroJFduGEYIBOxkY1` * **Android client** * Name: `ownCloud Android Client` * Callback URL: `oc://android.owncloud.com` * Client ID: `e4rAsNUSIUs0lF4nbv9FmCeUkTlV9GdgTLDH1b5uie7syb90SzEVrbN7HIpmWJeD` # Open WebUI > Sign in to Open WebUI with Pocket ID. ## Create groups in Pocket ID [Section titled “Create groups in Pocket ID”](#create-groups-in-pocket-id) *(Optional)* This step is recommended if you want Open WebUI to manage roles and groups. 1. In Pocket ID, open **Administration → User Groups** and click **Add Group**. 2. Create a group for users and a group for admins, for example with the **Name** `users` and `admins`. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Open WebUI` and add the callback URL `https://openwebui.example.com/oauth/oidc/callback`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Open WebUI [Section titled “Configure Open WebUI”](#configure-open-webui) Add the following to your Docker `.env` file for Open WebUI: ```ini ENABLE_OAUTH_SIGNUP=true OAUTH_CLIENT_ID= OAUTH_CLIENT_SECRET= OAUTH_PROVIDER_NAME=Pocket ID OPENID_PROVIDER_URL=https://id.example.com/.well-known/openid-configuration OAUTH_MERGE_ACCOUNTS_BY_EMAIL=true # For group management, you can use the following variables: ENABLE_OAUTH_ROLE_MANAGEMENT=true ENABLE_OAUTH_GROUP_MANAGEMENT=true ENABLE_OAUTH_GROUP_CREATION=true # Make sure these match the groups you created in Pocket ID OAUTH_ALLOWED_ROLES=users,admins OAUTH_ADMIN_ROLES=admins OAUTH_ROLES_CLAIM=groups OAUTH_SCOPES=openid email profile groups # Optional but useful variables: # So users are immediately added instead of being "pending" DEFAULT_USER_ROLE=user # Make Pocket ID the only auth method # comment out if you need access via password ENABLE_LOGIN_FORM=false # Make Pocket ID the source of truth for the profile pictures OAUTH_UPDATE_PICTURE_ON_LOGIN=true ``` We recommend keeping a separate admin account without OAuth in Open WebUI, so you don’t get locked out while testing the integration. See the [Open WebUI documentation](https://docs.openwebui.com/reference/env-configuration#oauth) for more information. # OpenCloud > Sign in to OpenCloud with Pocket ID. OpenCloud ships with a built-in identity provider (IDP), but it can be replaced with an external OIDC provider. This guide walks through replacing the internal IDP with Pocket ID. Replace `opencloud.example.com` with the domain of your OpenCloud instance and `id.example.com` with the domain of your Pocket ID instance. ## Key requirements [Section titled “Key requirements”](#key-requirements) OpenCloud enforces a few constraints on external OIDC providers: * All clients **must** be **public clients** using **PKCE** (Authorization Code + PKCE flow). There are no confidential clients. * Desktop and mobile clients use **predefined, hardcoded `client_id` values** (`OpenCloudDesktop`, `OpenCloudAndroid`, `OpenCloudIOS`). These must be registered in Pocket ID with those exact IDs; see [Create the desktop and mobile clients](#create-the-desktop-and-mobile-clients). * The provider must include a **role claim** in the access token. OpenCloud maps claim values to its internal roles (`opencloudAdmin`, `opencloudSpaceAdmin`, `opencloudUser`, `opencloudGuest`). ## Create groups in Pocket ID [Section titled “Create groups in Pocket ID”](#create-groups-in-pocket-id) In Pocket ID, open **Administration → User Groups** and click **Add Group** to create the following four groups. They are used both for access control and role assignment. | Name | Purpose | | ----------------------- | -------------------------------------- | | `opencloud_admins` | Maps to the `opencloudAdmin` role | | `opencloud_spaceadmins` | Maps to the `opencloudSpaceAdmin` role | | `opencloud_users` | Maps to the `opencloudUser` role | | `opencloud_guests` | Maps to the `opencloudGuest` role | After creating each group, open it and go to **Custom Claims**. Add a claim with the key `opencloud_role` and the value from the table below: | Group | Claim key | Claim value | | ----------------------- | ---------------- | --------------------- | | `opencloud_admins` | `opencloud_role` | `opencloudAdmin` | | `opencloud_spaceadmins` | `opencloud_role` | `opencloudSpaceAdmin` | | `opencloud_users` | `opencloud_role` | `opencloudUser` | | `opencloud_guests` | `opencloud_role` | `opencloudGuest` | Every user must belong to at least one of these groups. Users without a group can authenticate but receive an error inside OpenCloud. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) This is the client for the OpenCloud web frontend. 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `OpenCloud`, choose **Public Client** as the client type and add the callback URLs: ```plaintext https://opencloud.example.com/ https://opencloud.example.com/oidc-callback.html https://opencloud.example.com/oidc-silent-redirect.html ``` 3. Click **Create** and copy the **Client ID** (a UUID). You need it to [configure OpenCloud](#configure-opencloud). 4. On the client’s **General** tab, add `https://opencloud.example.com` under **Logout Callback URLs**, turn on **PKCE** and save. 5. On the client’s **Access** tab, select the four OpenCloud groups under **Allowed User Groups**. **No client secret is needed.** OpenCloud’s web frontend is a public SPA and never sends a `client_secret`. ## Create the desktop and mobile clients [Section titled “Create the desktop and mobile clients”](#create-the-desktop-and-mobile-clients) OpenCloud’s desktop and mobile clients send hardcoded `client_id` values that can’t be changed in the application. You must register clients in Pocket ID with those exact IDs instead of the auto-generated UUID. ### Desktop [Section titled “Desktop”](#desktop) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `OpenCloud Desktop`, choose **Public Client** as the client type and add the callback URLs: ```plaintext http://127.0.0.1 http://localhost ``` 3. Click **Set custom client ID** and enter `OpenCloudDesktop`. 4. Click **Create**. 5. On the client’s **General** tab, turn on **PKCE** and save. 6. On the client’s **Access** tab, select the four OpenCloud groups under **Allowed User Groups**. ### Android [Section titled “Android”](#android) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `OpenCloud Android`, choose **Public Client** as the client type and add the callback URL `oc://android.opencloud.eu`. 3. Click **Set custom client ID** and enter `OpenCloudAndroid`. 4. Click **Create**. 5. On the client’s **General** tab, turn on **PKCE** and save. 6. On the client’s **Access** tab, select the four OpenCloud groups under **Allowed User Groups**. ### iOS [Section titled “iOS”](#ios) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `OpenCloud iOS`, choose **Public Client** as the client type and add the callback URL `oc://ios.opencloud.eu`. 3. Click **Set custom client ID** and enter `OpenCloudIOS`. 4. Click **Create**. 5. On the client’s **General** tab, turn on **PKCE** and save. 6. On the client’s **Access** tab, select the four OpenCloud groups under **Allowed User Groups**. ## Configure OpenCloud [Section titled “Configure OpenCloud”](#configure-opencloud) Set the following environment variables on your OpenCloud deployment. Replace `id.example.com` with your Pocket ID domain and `` with the **Client ID** of the web frontend client. ```bash # Disable the built-in IDP OC_EXCLUDE_RUN_SERVICES=idp # External OIDC issuer OC_OIDC_ISSUER=https://id.example.com PROXY_OIDC_ISSUER=https://id.example.com # Web frontend client (Client ID of the web frontend client) WEB_OIDC_CLIENT_ID= WEB_OIDC_AUTHORITY=https://id.example.com WEB_OIDC_METADATA_URL=https://id.example.com/.well-known/openid-configuration WEB_OIDC_RESPONSE_TYPE=code WEB_OIDC_SCOPE=openid profile email groups # Proxy OIDC settings PROXY_OIDC_CLIENT_ID= PROXY_OIDC_REWRITE_WELLKNOWN=true PROXY_OIDC_ACCESS_TOKEN_VERIFY_METHOD=none # User auto-provisioning PROXY_AUTOPROVISION_ACCOUNTS=true PROXY_AUTOPROVISION_CLAIM_USERNAME=preferred_username PROXY_AUTOPROVISION_CLAIM_EMAIL=email PROXY_AUTOPROVISION_CLAIM_DISPLAYNAME=name PROXY_AUTOPROVISION_CLAIM_GROUPS=groups # User identity mapping PROXY_USER_OIDC_CLAIM=preferred_username PROXY_USER_CS3_CLAIM=username # Role assignment — reads the opencloud_role custom claim set on Pocket ID groups PROXY_ROLE_ASSIGNMENT_DRIVER=oidc PROXY_ROLE_ASSIGNMENT_OIDC_CLAIM=opencloud_role # Graph GRAPH_ASSIGN_DEFAULT_USER_ROLE=false GRAPH_USERNAME_MATCH=none ``` ### Content Security Policy [Section titled “Content Security Policy”](#content-security-policy) If you use a CSP config file, allow connections to your Pocket ID instance: ```yaml directives: connect-src: - "'self'" - 'https://id.example.com' - 'wss://id.example.com' ``` > The WebSocket entry must use `wss://id.example.com`, with no trailing slash and no embedded `https://` prefix. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### “Logging you in — Please wait, you are being redirected” (stuck) [Section titled ““Logging you in — Please wait, you are being redirected” (stuck)”](#logging-you-in--please-wait-you-are-being-redirected-stuck) The OIDC callback is reached, but the token exchange fails silently. **Verify that the Pocket ID client has both Public Client and PKCE turned on.** A confidential client without PKCE causes the redirect to complete but the code exchange to fail, because the browser never sends a `client_secret`. ### “This could be because of a routine safety log out, or because your account is either inactive or not yet authorized for use” [Section titled ““This could be because of a routine safety log out, or because your account is either inactive or not yet authorized for use””](#this-could-be-because-of-a-routine-safety-log-out-or-because-your-account-is-either-inactive-or-not-yet-authorized-for-use) The user authenticated successfully, but OpenCloud couldn’t assign a role. Check: 1. **The user isn’t in any OpenCloud group**: add the user to one of the four groups in Pocket ID. 2. **The `opencloud_role` custom claim is missing**: verify each group has the claim configured as described in [Create groups in Pocket ID](#create-groups-in-pocket-id). 3. **The claim name doesn’t match**: confirm `PROXY_ROLE_ASSIGNMENT_OIDC_CLAIM` equals `opencloud_role`. ### Desktop or mobile client receives “unauthorized_client” [Section titled “Desktop or mobile client receives “unauthorized_client””](#desktop-or-mobile-client-receives-unauthorized_client) The predefined client ID (`OpenCloudDesktop`, `OpenCloudAndroid` or `OpenCloudIOS`) doesn’t exist in Pocket ID. Follow [Create the desktop and mobile clients](#create-the-desktop-and-mobile-clients) to register it. ### Users can sign in but see an empty file list or permission errors [Section titled “Users can sign in but see an empty file list or permission errors”](#users-can-sign-in-but-see-an-empty-file-list-or-permission-errors) `PROXY_USER_OIDC_CLAIM` must identify users uniquely and consistently across logins. `preferred_username` works well with Pocket ID. Avoid `email` if users are allowed to change their email address in Pocket ID. # Opengist > Sign in to Opengist with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Opengist` and add the callback URL `https://opengist.example.com/oauth/oidc/callback`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Opengist [Section titled “Configure Opengist”](#configure-opengist) Add the following configuration to your Opengist `config.yml` file: ```yaml oauth: oidc: provider-name: "PocketID" client-key: "" secret: "" discovery-url: "https://id.example.com/.well-known/openid-configuration" group-claim-name: "opengist" admin-group: "opengist-admins" ``` ### Environment variables (alternative) [Section titled “Environment variables (alternative)”](#environment-variables-alternative) You can also configure Opengist using environment variables: ```bash OG_OIDC_PROVIDER_NAME=PocketID OG_OIDC_CLIENT_KEY= OG_OIDC_SECRET= OG_OIDC_DISCOVERY_URL=https://id.example.com/.well-known/openid-configuration OG_OIDC_GROUP_CLAIM_NAME=opengist OG_OIDC_ADMIN_GROUP=opengist-admins ``` ## Testing [Section titled “Testing”](#testing) 1. Restart Opengist. 2. Open your Opengist instance. 3. You should see a **Login with OIDC** button on the login page. 4. Click it to be redirected to Pocket ID and sign in with your passkey. ## Admin group [Section titled “Admin group”](#admin-group) To grant admin privileges to specific users, configure the `admin-group` parameter. Users who belong to this group in Pocket ID have admin access in Opengist. 1. In Pocket ID, open **Administration → User Groups**, click **Add Group** and create a group with the **Name** `opengist-admins` (or your preferred name). 2. Add the users who should have admin privileges to this group. 3. Configure Opengist to use this group as shown in the examples above. ## Notes [Section titled “Notes”](#notes) * Make sure the callback URL in Pocket ID exactly matches what’s configured in Opengist. * The discovery URL must point to the `.well-known/openid-configuration` endpoint of your Pocket ID instance. * Users are automatically created in Opengist on their first sign-in. * Admin group membership is checked on each sign-in, so changes in Pocket ID take effect immediately. # OpenPubKey SSH > Sign in to SSH servers with OpenPubKey SSH (opkssh) and Pocket ID. This guide assumes OpenPubKey SSH (opkssh) is installed on both the server and the client. For installation instructions for different operating systems, see . ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `OpenPubKey SSH`, choose **Public Client** as the client type and add the callback URLs: ```plaintext http://localhost:3000/login-callback http://localhost:10001/login-callback http://localhost:11110/login-callback ``` 3. Click **Create** and copy the **Client ID**. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Collect user and audience information [Section titled “Collect user and audience information”](#collect-user-and-audience-information) 1. Open the client in Pocket ID and click **OIDC Data Preview** at the top of the page. 2. Select the user and copy the `aud` and `sub` values. ## Configure the provider on the server [Section titled “Configure the provider on the server”](#configure-the-provider-on-the-server) 1. Sign in to the server running SSH. Ubuntu is used in this example, but other Linux distributions, Windows Server and Windows 11 are supported as well. 2. Edit the providers file, located at `/etc/opk/providers` by default on Linux. 3. Add the following line to the bottom of the file: ```plaintext https://id.example.com 24h ``` * Replace `` with the `aud` value you copied above. * `24h` is the token lifetime. You can change it to a different value, such as `12h` or `6h`. 4. Remove the default providers from the file if you don’t need them, and save it. ## Map users and groups on the server [Section titled “Map users and groups on the server”](#map-users-and-groups-on-the-server) 1. Map OIDC users and groups to a local user by running the following command on the server: ```bash opkssh add ``` 2. User example (replace `` with the `sub` value you copied above): ```bash opkssh add root https://id.example.com ``` 3. Group example (assumes there is a Pocket ID group named `opkssh_users`): ```bash opkssh add root oidc:groups:opkssh_users https://id.example.com ``` Pocket ID only sends the groups claim when the `groups` scope is requested, so the client configuration below includes it. Note User and group mappings are stored in `/etc/opk/auth_id`. This file applies server-wide and requires root permissions to edit. Users can also configure their own OIDC mappings in `~/.opk/auth_id`, which doesn’t require root permissions. In that file, users can only map OIDC users to their own local user account. For more information, see . ## Configure the client [Section titled “Configure the client”](#configure-the-client) 1. In a terminal on the client, run the following command: ```bash opkssh login --create-config ``` This creates the file `~/.opk/config.yml` in your home folder. 2. Add the following to the end of the file and replace `` with the **Client ID** from Pocket ID: ```yaml - alias: pocket-id issuer: https://id.example.com client_id: scopes: openid email groups access_type: offline prompt: consent redirect_uris: - http://localhost:3000/login-callback - http://localhost:10001/login-callback - http://localhost:11110/login-callback ``` 3. Remove the other providers if you don’t need them and save the file. ## Sign in [Section titled “Sign in”](#sign-in) 1. On the client, run the following command: ```bash opkssh login pocket-id ``` This opens the Pocket ID sign-in page in your default browser. 2. After signing in, you can close the page. 3. Back in the terminal, run `ssh user@server`, where `user` is the mapped local user and `server` is the server running opkssh. You’re signed in to the server automatically. You can also run `opkssh login` without the alias. This opens a page in your browser with a list of the configured providers, where you choose Pocket ID. You can configure multiple servers to use the same Pocket ID client for opkssh. If you want to limit different Pocket ID users to different servers, you need multiple clients. # Outline > Sign in to the Outline wiki with Pocket ID. Setting up [Outline](https://docs.getoutline.com/s/hosting/doc/oidc-8CPBm6uC0I) to authenticate with Pocket ID can be done with the configuration below. ## Requirements [Section titled “Requirements”](#requirements) * Your Outline and Pocket ID server URLs must both use HTTPS. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Outline` and add the callback URL `https://outline.example.com/auth/oidc.callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL**, the **Token URL**, the **Userinfo URL** and the **Logout URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Outline [Section titled “Configure Outline”](#configure-outline) 1. Add the following to your Outline container’s `docker.env`: ```ini OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= OIDC_AUTH_URI=https://id.example.com/authorize OIDC_TOKEN_URI=https://id.example.com/api/oidc/token OIDC_USERINFO_URI=https://id.example.com/api/oidc/userinfo OIDC_LOGOUT_URI=https://id.example.com/api/oidc/end-session OIDC_DISPLAY_NAME=Pocket ID OIDC_USERNAME_CLAIM=preferred_username OIDC_SCOPES=openid profile email groups ``` 2. Restart your Outline container: ```bash docker compose down docker compose up -d ``` 3. Sign in to Outline with Pocket ID to test it. 4. Review and update the SSO settings under **Settings → Workspace → Security**. # Pangolin > Sign in to Pangolin with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Pangolin` and add the callback URL `https://pangolin.example.com/auth/idp//oidc/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL** and the **Token URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. Pangolin shows the ID for `` only after you create the identity provider, so you update the callback URL later. ## Configure Pangolin [Section titled “Configure Pangolin”](#configure-pangolin) 1. Sign in to Pangolin with your superuser account. 2. Under **Server Admin**, select **Identity Providers**, then **Add Identity Provider**. 3. Fill in the fields: * **Identity Provider** * **Name**: `Pocket ID` (or anything you want) * Enable **Auto Provision Users** (only if you want auto provisioning) * **Provider Type**: select **OAuth2/OIDC**. * **OAuth2/OIDC Configuration** * **Client ID**: the **Client ID** from Pocket ID. * **Client Secret**: the **Client secret** from Pocket ID. * **Authorization URL**: the **Authorization URL** from Pocket ID. * **Token URL**: the **Token URL** from Pocket ID. * **Token Configuration** * **Identifier Path**: one of `email`, `preferred_username` or `sub` (Advanced) * **Email Path**: `email` * **Name Path**: `name` * **Scopes**: `openid profile email` (include `groups` for auto provisioning) 4. Save the new identity provider. 5. Copy the **Redirect URL** shown by Pangolin and update the callback URL of the client in Pocket ID so that the two values match exactly. ## Create users [Section titled “Create users”](#create-users) Create users either with auto provisioning or manually. Once you have created a user, sign out of Pangolin and sign in with Pocket ID to test it. ### Auto provisioning [Section titled “Auto provisioning”](#auto-provisioning) See [Pangolin’s docs on auto provisioning](https://docs.pangolin.net/manage/identity-providers/auto-provisioning) for more advanced setups. 1. In Pocket ID, open **Administration → User Groups**, click **Add Group** and create a group: * **Friendly Name**: `Admin` (or anything you want) * **Name**: `admin` (or anything you want) 2. Add the desired admin users to the group. 3. In Pangolin, under **Server Admin → Identity Providers**, edit the Pocket ID provider and make sure **Auto Provision Users** is enabled and the **Scopes** include `groups`. 4. Open **Organization Policies**. 5. Under **Default Mappings**, set: * **Default Role Mapping**: `contains(groups, 'admin') && 'Admin' || 'Member'` (replace `admin` with the name of your user group) * **Default Organization Mapping**: `'YOUR PANGOLIN ORGANIZATION ID'` (see the examples of [advanced mappings in Pangolin’s docs](https://docs.pangolin.net/manage/identity-providers/auto-provisioning#selecting-organizations)) 6. Click **Save Default Mappings**. ### Manually [Section titled “Manually”](#manually) 1. In Pangolin, go to your organization, select **Users**, then **Create User**. 2. Select **External User**, select your Pocket ID identity provider and fill in the relevant details. Enter the value that matches your **Identifier Path** in the **Username** field: * `email` is your Pocket ID email. * `preferred_username` is your Pocket ID username. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### User not provisioned (Manual) in the system [Section titled “User not provisioned (Manual) in the system”](#user-not-provisioned-manual-in-the-system) Make sure you have created a user in Pangolin and that its **Username** matches the **Identifier Path** used. ### After signing in with OIDC (auto provisioned): `There was a problem connecting to Pocket ID. Please contact your administrator.` [Section titled “After signing in with OIDC (auto provisioned): There was a problem connecting to Pocket ID. Please contact your administrator.”](#after-signing-in-with-oidc-auto-provisioned-there-was-a-problem-connecting-to-pocket-id-please-contact-your-administrator) In Pangolin, under **Server Admin → Identity Providers**, edit the Pocket ID provider and make sure the **Scopes** include `groups`. ### Invalid callback URL, it might be necessary for an admin to fix this [Section titled “Invalid callback URL, it might be necessary for an admin to fix this”](#invalid-callback-url-it-might-be-necessary-for-an-admin-to-fix-this) The callback URL isn’t set correctly in Pocket ID. Make sure it matches the **Redirect URL** in your Pangolin OIDC configuration, for example `https://pangolin.example.com/auth/idp/1/oidc/callback`. # Paperless-ngx > Sign in to the Paperless-ngx document manager with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Paperless-ngx` and add the callback URL `https://paperless-ngx.example.com/accounts/oidc/pocket-id/login/callback/`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Paperless-ngx [Section titled “Configure Paperless-ngx”](#configure-paperless-ngx) 1. Add the following environment variables to the Paperless-ngx webserver container. See the [Paperless-ngx documentation](https://docs.paperless-ngx.com/configuration/#PAPERLESS_SOCIALACCOUNT_PROVIDERS) for more information. ```ini PAPERLESS_APPS=allauth.socialaccount.providers.openid_connect PAPERLESS_SOCIALACCOUNT_PROVIDERS={"openid_connect":{"SCOPE":["openid","profile","email"],"OAUTH_PKCE_ENABLED":true,"APPS":[{"provider_id":"pocket-id","name":"Pocket ID","client_id":"","secret":"","settings":{"server_url":"https://id.example.com"}}]}} ``` The `provider_id` value (here `pocket-id`) must match the one in the callback URL in Pocket ID. 2. Restart your Docker containers. 3. Sign in to Paperless-ngx with Pocket ID to test it. ## Link an existing account [Section titled “Link an existing account”](#link-an-existing-account) To link your existing Paperless-ngx user to the user in Pocket ID: 1. Sign in to Paperless-ngx with password authentication. 2. Click your user name in the top right corner and click **My Profile**. 3. Link the account to Pocket ID with the **Connect new social account** option. # PatchMon > Sign in to PatchMon with Pocket ID. Replace `patchmon.example.com` with the domain of your PatchMon frontend and `id.example.com` with the domain of your Pocket ID instance. ## Requirements [Section titled “Requirements”](#requirements) * PatchMon 1.4.0 or later (PatchMon added OIDC SSO in version 1.4.0) ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `PatchMon` and add the callback URL `https://patchmon.example.com/api/v1/auth/oidc/callback`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **General** tab, turn on **PKCE**, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure PatchMon [Section titled “Configure PatchMon”](#configure-patchmon) This example uses the Docker Compose deployment of PatchMon. See the [official docs](https://docs.patchmon.net/books/patchmon-application-documentation/page/setting-up-oidc-sso-single-sign-on-integration) for more information. 1. Add or edit the following lines in your PatchMon `.env` file, with the **OIDC Discovery URL**, **Client ID** and **Client secret** from Pocket ID: ```ini OIDC_ENABLED=true OIDC_ISSUER_URL= OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= OIDC_REDIRECT_URI=https://patchmon.example.com/api/v1/auth/oidc/callback OIDC_SCOPES=openid email profile OIDC_AUTO_CREATE_USERS=true OIDC_DEFAULT_ROLE=user OIDC_DISABLE_LOCAL_AUTH=false OIDC_BUTTON_TEXT=Login with PocketID OIDC_SYNC_ROLES=false ``` 2. Save and redeploy PatchMon, then sign in with Pocket ID to test it. ## Group claim [Section titled “Group claim”](#group-claim) You can automatically assign permissions based on group membership. Group matching is case-insensitive, so `patchmon admins` matches `PatchMon Admins`. ### Create groups in Pocket ID [Section titled “Create groups in Pocket ID”](#create-groups-in-pocket-id) 1. In Pocket ID, open **Administration → User Groups** and click **Add Group** to create a group for every role you want to use. 2. Add users to the groups depending on the permissions you want them to have. You only need to define the groups you intend to use. Any variables left unset are ignored. ### PatchMon group environment variables [Section titled “PatchMon group environment variables”](#patchmon-group-environment-variables) Change these values in your `.env` file: * `OIDC_SCOPES` → `OIDC_SCOPES=openid email profile groups` * `OIDC_SYNC_ROLES` → `OIDC_SYNC_ROLES=true` Then add the groups for the roles you want to manage with Pocket ID: ```ini OIDC_ADMIN_GROUP=PatchMon Admins OIDC_USER_GROUP=PatchMon Users OIDC_SUPERADMIN_GROUP=PatchMon SuperAdmins OIDC_HOST_MANAGER_GROUP=PatchMon Host Managers OIDC_READONLY_GROUP=PatchMon Readonly ``` ## Sources [Section titled “Sources”](#sources) * * # Penpot > Sign in to the Penpot design tool with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * Self-hosted [Penpot](https://help.penpot.app/technical-guide/configuration/#authentication-providers) * HTTPS connection to your Penpot instance ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Penpot` and add the callback URL `https://penpot.example.com/api/auth/oidc/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Verify emails in Pocket ID [Section titled “Verify emails in Pocket ID”](#verify-emails-in-pocket-id) Open **Administration → Users** and select each user that should have access. If the icon next to the email isn’t green, click it to mark the email as verified, then save. Note Penpot only links Pocket ID to an existing profile, for example one created with a password, if Pocket ID returns a verified email that matches it. Otherwise the sign-in ends with `error=auth-provider-not-allowed` in the address bar. ## Configure Penpot [Section titled “Configure Penpot”](#configure-penpot) Penpot is configured with environment variables in its `docker-compose.yml`. 1. Add the `enable-login-with-oidc` flag to `PENPOT_FLAGS`, next to the flags already there: ```yaml x-flags: &penpot-flags PENPOT_FLAGS: enable-login-with-oidc ``` 2. Add the OIDC variables to the `penpot-backend` service, with the values from Pocket ID: ```yaml PENPOT_OIDC_BASE_URI: https://id.example.com PENPOT_OIDC_CLIENT_ID: PENPOT_OIDC_CLIENT_SECRET: ``` 3. *Optional:* If the Pocket ID hostname resolves to a private, loopback or otherwise internal address, allow it through Penpot’s SSRF protection: ```yaml PENPOT_SSRF_ALLOWED_HOSTS: "id.example.com" ``` 4. *Optional:* If the browser reaches Pocket ID at a public address but the backend has to use an internal one, which is common when running Docker on a Synology NAS, pin the hostname on the `penpot-backend` service: ```yaml extra_hosts: - "id.example.com:" ``` ### Automatic user creation [Section titled “Automatic user creation”](#automatic-user-creation) Penpot doesn’t create new profiles from OIDC sign-ins by default. To let new users sign up with their Pocket ID account, add the `enable-oidc-registration` flag to `PENPOT_FLAGS`. ### Disable login with password [Section titled “Disable login with password”](#disable-login-with-password) To harden security, disable password login by adding the `disable-login-with-password` flag to `PENPOT_FLAGS`. Keep a working recovery path, such as admin access to Pocket ID and the Penpot database, before you do. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) | Error in the address bar after returning from Pocket ID | Cause | Fix | | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | `error=unable-to-auth&hint=uri+target+is+not+allowed` | Penpot’s SSRF protection blocked the backend’s request to Pocket ID, because the hostname resolves to a private or loopback address | Add the Pocket ID hostname to `PENPOT_SSRF_ALLOWED_HOSTS` and restart `penpot-backend` | | `error=auth-provider-not-allowed` | The email belongs to an existing profile, for example one created with a password, but isn’t verified in Pocket ID | Mark the user’s email as verified in Pocket ID | | `error=registration-disabled` | No Penpot profile exists for the email and registration is disabled | Add the `enable-oidc-registration` flag to `PENPOT_FLAGS` | ## Sources [Section titled “Sources”](#sources) * [Penpot configuration guide](https://help.penpot.app/technical-guide/configuration/#authentication-providers) # pgAdmin > Sign in to the pgAdmin PostgreSQL management tool with Pocket ID. Replace `pgadmin.example.com` with the URL of your pgAdmin instance and `id.example.com` with the URL of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `pgAdmin` and add the callback URL `https://pgadmin.example.com/oauth2/authorize`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure pgAdmin [Section titled “Configure pgAdmin”](#configure-pgadmin) 1. Add the following to the `config_local.py` file for pgAdmin: ```python AUTHENTICATION_SOURCES = ['oauth2', 'internal'] # This keeps internal authentication enabled as well as oauth2 OAUTH2_AUTO_CREATE_USER = True OAUTH2_CONFIG = [{ 'OAUTH2_NAME' : 'pocketid', 'OAUTH2_DISPLAY_NAME' : 'Pocket ID', 'OAUTH2_CLIENT_ID' : '', 'OAUTH2_CLIENT_SECRET' : '', 'OAUTH2_TOKEN_URL' : 'https://id.example.com/api/oidc/token', 'OAUTH2_AUTHORIZATION_URL' : 'https://id.example.com/authorize', 'OAUTH2_API_BASE_URL' : 'https://id.example.com', 'OAUTH2_USERINFO_ENDPOINT' : 'https://id.example.com/api/oidc/userinfo', 'OAUTH2_SERVER_METADATA_URL' : 'https://id.example.com/.well-known/openid-configuration', 'OAUTH2_SCOPE' : 'openid email profile', 'OAUTH2_ICON' : 'fa-openid', 'OAUTH2_BUTTON_COLOR' : '#fd4b2d' # Can select any color you would like here. }] ``` Make sure to replace `https://id.example.com` with your actual Pocket ID URL. # PhotoPrism > Sign in to the PhotoPrism photo library with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `PhotoPrism` and add the callback URL `https://photoprism.example.com/api/v1/oidc/redirect`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, set **Client Launch URL** to `https://photoprism.example.com`, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure PhotoPrism [Section titled “Configure PhotoPrism”](#configure-photoprism) Check out PhotoPrism’s [OIDC Docs](https://docs.photoprism.app/developer-guide/api/oidc/) for more details. If you have PhotoPrism Pro, see the additional options in the [Pro OIDC Docs](https://www.photoprism.app/pro/kb/config-options). Configure the following environment variables: ```yaml # Required PHOTOPRISM_OIDC_URI: https://id.example.com PHOTOPRISM_OIDC_CLIENT: PHOTOPRISM_OIDC_SECRET: # Enable Auto User Registration PHOTOPRISM_OIDC_REGISTER: true/false ``` Optional configuration: ```yaml # Custom Identity Provider Name PHOTOPRISM_OIDC_PROVIDER: Pocket ID PHOTOPRISM_OIDC_REDIRECT: true/false PHOTOPRISM_OIDC_ICON: ``` Note Unless security settings are changed, the icon must be an accessible path from the PhotoPrism container or served via the same domain as PhotoPrism. See this [GitHub issue](https://github.com/photoprism/photoprism/discussions/2622) for more details. # Pinepods > Sign in to the Pinepods podcast manager with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Pinepods` and add the callback URL `https://pinepods.example.com/api/auth/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL**, the **Token URL** and the **Userinfo URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Pinepods [Section titled “Configure Pinepods”](#configure-pinepods) OIDC can be configured through the UI or through environment variables. Environment variables require version 0.8.2+. ### Using the UI [Section titled “Using the UI”](#using-the-ui) Only admin users can configure OIDC/SSO settings. 1. Open Pinepods and navigate to **Settings → Admin Settings → OIDC/SSO Settings**. 2. Fill in the required fields: * **Provider Name**: `Pocket ID` * **Client ID**: the **Client ID** from Pocket ID. * **Client Secret**: the **Client secret** from Pocket ID. * **Authorization URL**: the **Authorization URL** from Pocket ID. * **Token URL**: the **Token URL** from Pocket ID. * **User Info URL**: the **Userinfo URL** from Pocket ID. 3. *(Optional)* Change the button text, for example to `Login with Pocket ID`. ### Using environment variables [Section titled “Using environment variables”](#using-environment-variables) This method requires Pinepods v0.8.2+. Check out the [Pinepods documentation](https://www.pinepods.online/docs/tutorial-basics/environment-variables#oidc-openid-connect-configuration) for the full list of available environment variables. Example config using a `.env` file: ```sh # Basic OIDC Configuration OIDC_PROVIDER_NAME: "Pocket ID" OIDC_CLIENT_ID: "" OIDC_CLIENT_SECRET: "" OIDC_AUTHORIZATION_URL: "https://id.example.com/oauth2/authorize" OIDC_TOKEN_URL: "https://id.example.com/oauth2/token" OIDC_USER_INFO_URL: "https://id.example.com/oauth2/userinfo" # Optional OIDC Customization OIDC_BUTTON_TEXT: "Login with Pocket ID" OIDC_SCOPE: "openid email profile groups" OIDC_BUTTON_COLOR: "#1a365d" OIDC_BUTTON_TEXT_COLOR: "#ffffff" # Role Mapping OIDC_ROLES_CLAIM: "groups" OIDC_USER_ROLE: "pinepods-users" OIDC_ADMIN_ROLE: "pinepods-admins" # Disable standard login (optional) OIDC_DISABLE_STANDARD_LOGIN: true ``` # Pingvin Share > Sign in to the Pingvin Share file sharing platform with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [Pingvin Share](https://stonith404.github.io/pingvin-share/setup/oauth2login#openid-connect) * HTTPS connection to your Pingvin Share server ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Pingvin Share` and add the callback URL `https://pingvin.example.com/api/oauth/callback/oidc`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Pingvin Share [Section titled “Configure Pingvin Share”](#configure-pingvin-share) 1. Open Pingvin Share and navigate to **Administration → Configuration → Social Login**. 2. Scroll down and fill in the fields: * **OpenID Connect**: `Enabled` * **OpenID Connect Discovery URI**: the **OIDC Discovery URL** from Pocket ID. * **Sign out from OpenID Connect**: `Enabled` (if desired) * **OpenID Connect scope**: `openid email profile groups` ## Control access with groups [Section titled “Control access with groups”](#control-access-with-groups) To control **general** and **admin** access to Pingvin Share using Pocket ID groups: 1. Open Pingvin Share and navigate to **Administration → Configuration → Social Login**. 2. Scroll down and fill in the following: * **OpenID Connect scope**: `openid email profile groups` * **Path to roles in OpenID Connect token**: `groups` * **OpenID Connect role for general access**: `pingvin` (or a similar group name from Pocket ID) * **OpenID Connect role for admin access**: `pingvin_admin` (or a similar group name from Pocket ID) # Planka > Sign in to the Planka project board with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [Planka](https://docs.planka.cloud/) * HTTPS connection to your Planka instance ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Planka` and add the callback URL `https://planka.example.com/oidc-callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Planka [Section titled “Configure Planka”](#configure-planka) 1. Set the following environment variables in your Planka instance: ```ini OIDC_ISSUER=https://id.example.com OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= ``` 2. Restart Planka and sign in with Pocket ID to test it. ## Control admin access with groups [Section titled “Control admin access with groups”](#control-admin-access-with-groups) To control **admin** access to Planka using Pocket ID groups: 1. Set the following additional environment variables in your Planka instance: ```ini OIDC_SCOPES=openid profile email groups OIDC_ROLES_ATTRIBUTE=groups OIDC_ADMIN_ROLES= ``` 2. Restart Planka. ## Additional information [Section titled “Additional information”](#additional-information) See the [Planka OIDC documentation](https://docs.planka.cloud/docs/configuration/oidc) for more information. # Portainer > Sign in to the Portainer container management platform with Pocket ID. Replace `portainer.example.com` with the URL of your Portainer instance and `id.example.com` with the URL of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Portainer` and add the callback URL `https://portainer.example.com/`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL**, the **Token URL**, the **Userinfo URL** and the **Logout URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Portainer [Section titled “Configure Portainer”](#configure-portainer) * While initially setting up OAuth in Portainer, it’s recommended to keep **Hide internal authentication prompt** set to `Off` in case you need a fallback login. * This guide does **not** cover how to set up group claims in Portainer. Tip Make sure to enable the **Automatic user provisioning** option so users are auto-created in Portainer. 1. Open the Portainer web interface and navigate to **Settings → Authentication**. 2. Select **Custom OAuth Provider**. 3. Paste the **Client ID** from Pocket ID into the **Client ID** field in Portainer. 4. Paste the **Client secret** from Pocket ID into the **Client Secret** field in Portainer. 5. Paste the **Authorization URL** from Pocket ID into the **Authorization URL** field in Portainer. 6. Paste the **Token URL** from Pocket ID into the **Access token URL** field in Portainer. 7. Paste the **Userinfo URL** from Pocket ID into the **Resource URL** field in Portainer. 8. Set **Redirect URL** to `https://portainer.example.com/`. 9. Paste the **Logout URL** from Pocket ID into the **Logout URL** field in Portainer. 10. Set **User identifier** to `preferred_username`. This uses the user’s username instead of the email. 11. Set **Scopes** to `email openid profile`. 12. Set **Auth Style** to `Auto detect`. 13. Save the settings and sign in with the OAuth button to test it. # Postiz > Sign in to the Postiz social media scheduling tool with Pocket ID. Postiz is an open-source, self-hosted social media scheduling tool that supports platforms like X (formerly Twitter), Bluesky, Mastodon, Discord, and others. This guide configures Postiz to use Pocket ID as an authentication provider. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Postiz` and add the callback URL `https://postiz.example.com/settings`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Postiz [Section titled “Configure Postiz”](#configure-postiz) Set up Postiz as described in the [official documentation](https://docs.postiz.com/installation/docker-compose). Modify the following environment variables in the `docker-compose.yml` file: ```yaml NEXT_PUBLIC_POSTIZ_OAUTH_DISPLAY_NAME: "Pocket ID" NEXT_PUBLIC_POSTIZ_OAUTH_LOGO_URL: "https://raw.githubusercontent.com/pocket-id/pocket-id/refs/heads/main/frontend/static/img/static-logo.svg" POSTIZ_GENERIC_OAUTH: "true" POSTIZ_OAUTH_URL: "https://id.example.com" POSTIZ_OAUTH_AUTH_URL: "https://id.example.com/authorize" POSTIZ_OAUTH_TOKEN_URL: "https://id.example.com/api/oidc/token" POSTIZ_OAUTH_USERINFO_URL: "https://id.example.com/api/oidc/userinfo" POSTIZ_OAUTH_CLIENT_ID: "" POSTIZ_OAUTH_CLIENT_SECRET: "" ``` ## Further reading [Section titled “Further reading”](#further-reading) * [Postiz Documentation for OIDC Configuration](https://docs.postiz.com/configuration/oauth) # Proxmox > Sign in to Proxmox VE with Pocket ID. Replace `proxmox.example.com` with the URL of your Proxmox instance and `id.example.com` with the URL of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Proxmox` and add the callback URL `https://proxmox.example.com`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Proxmox [Section titled “Configure Proxmox”](#configure-proxmox) 1. Open the Proxmox console and navigate to **Datacenter → Permissions → Realms**. 2. Add a new **OpenID Connect Server** realm. 3. Enter `https://id.example.com` for the **Issuer URL**. 4. Enter a name for the realm of your choice, for example `PocketID`. 5. Paste the **Client ID** from Pocket ID into the **Client ID** field in Proxmox. 6. Paste the **Client secret** from Pocket ID into the **Client Key** field in Proxmox. 7. *(Optional)* Check the **Default** box if you want this to be the default realm Proxmox uses when signing in. 8. Check the **Autocreate Users** checkbox. This automatically creates users in Proxmox if they don’t exist. 9. Select `username` for the **Username Claim** dropdown. This is a personal preference and controls how the username is shown, for example `username = username@PocketID` or `email = username@example@PocketID`. 10. Leave the rest as defaults and click **OK** to save the new realm. 11. Sign in to Proxmox with a Pocket ID user to autocreate the user account. ### User permissions [Section titled “User permissions”](#user-permissions) For individual standalone user management (without groups): * Navigate to **Datacenter → Permissions**. * Click **Add** and select **User Permission**. * Set **Path** to `/` for the entire datacenter or specify a specific VM or container path. * Select the newly created `YourPocketUsername@PocketID` account. * Set **Role** to `Administrator` for this account. ### Group permissions [Section titled “Group permissions”](#group-permissions) Caution This is just an example of how to set up RBAC based on OIDC groups. You may want to adjust the roles and permissions based on your specific needs. This part is optional. If you want to restrict access to specific groups and allow specific roles based on user groups, follow these steps. #### In Pocket ID [Section titled “In Pocket ID”](#in-pocket-id) 1. Open **Administration → User Groups** and click **Add Group** to create two groups, for example `Proxmox Users` and `Proxmox Admins`. 2. Add the users you want to allow access to Proxmox to these groups. 3. On the `Proxmox` client’s **Access** tab, select the `Proxmox Users` and `Proxmox Admins` groups under **Allowed User Groups** and save. #### In Proxmox [Section titled “In Proxmox”](#in-proxmox) 1. In Proxmox, edit the `PocketID` realm you created earlier. 2. Set **Scope** to `openid profile email groups`. 3. Set **Group Claim** to `groups` and save the realm. 4. Check the **Autocreate Groups** checkbox to have Proxmox automatically create groups based on the groups in Pocket ID. 5. Sign in to Proxmox with a user that is in the `Proxmox Users` or `Proxmox Admins` group. 6. You should now see the user groups in Proxmox, and you can assign permissions: * Navigate to **Datacenter → Permissions**. * Click **Add** and select **Group Permission**. * Set **Path** to `/` for the entire datacenter or specify a specific VM or container path. * Select the `Proxmox Users@PocketID` or `Proxmox Admins@PocketID` group. * Set **Role** to `PVEAudit` for `Proxmox Users@PocketID`, and `Administrator` for `Proxmox Admins@PocketID`. # Proxmox Backup Server > Sign in to Proxmox Backup Server with Pocket ID. Replace `pbs.example.com` with the URL of your Proxmox Backup Server instance and `id.example.com` with the URL of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Proxmox Backup Server` and add the callback URL `https://pbs.example.com`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Proxmox Backup Server [Section titled “Configure Proxmox Backup Server”](#configure-proxmox-backup-server) 1. Open the PBS console and navigate to **Configuration → Access Control → Realms**. 2. Add a new **OpenID Connect Server** realm. 3. Enter `https://id.example.com` for the **Issuer URL**. 4. Enter a name for the realm of your choice, for example `PocketID`. 5. Paste the **Client ID** from Pocket ID into the **Client ID** field in PBS. 6. Paste the **Client secret** from Pocket ID into the **Client Key** field in PBS. 7. *(Optional)* Check the **Default** box if you want this to be the default realm PBS uses when signing in. 8. Check the **Autocreate Users** checkbox. This automatically creates users in PBS if they don’t exist. 9. Select `username` for the **Username Claim** dropdown. This is a personal preference and controls how the username is shown, for example `username = username@PocketID` or `email = username@example@PocketID`. 10. Leave the rest as defaults and click **OK** to save the new realm. 11. Sign in with the Pocket ID account to create the user. Once the user has been created in PBS, finish the setup: 1. Sign back in as a local administrator to grant permissions. 2. In PBS, edit the `PocketID` realm you created earlier. 3. Set **Scope** to `openid profile email groups`. 4. You should now see the user groups in PBS, and you can assign permissions: * Navigate to **Configuration → Access Control → Permissions**. * Click **Add** and select **User Permission**. * Set **Path** to `/` for the entire datacenter or specify a specific VM or container path. * Select the `YourUsername@PocketID` user. * Set **Role** to `Administrator`. # Rallly > Sign in to the Rallly scheduling tool with Pocket ID. Replace `rallly.example.com` with the URL of your Rallly instance and `id.example.com` with the URL of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Rallly` and add the callback URL `https://rallly.example.com/api/auth/callback/oidc`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Rallly [Section titled “Configure Rallly”](#configure-rallly) If you follow the [Rallly Docker setup](https://support.rallly.co/self-hosting/installation/docker#setup-instructions), you are encouraged to create a `config.env` file in the root of your Rallly project directory. This file sets the environment variables for the Rallly web server container. The `config.env` file should look like this: ```ini # other environment variables... OIDC_DISCOVERY_URL=https://id.example.com/.well-known/openid-configuration OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= OIDC_ISSUER_URL=https://id.example.com ``` Restart your Docker containers and sign in to Rallly with Pocket ID to test it. # RDP Gateway > Sign in to RDP Gateway with Pocket ID to connect to remote desktops. [RDPGW](https://github.com/bolkedebruin/rdpgw) allows you to connect with the official Microsoft RDP clients to remote desktops over HTTPS. The following example deploys RDPGW behind a Caddy reverse proxy with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `RDP Gateway` and add the callback URL `https://rd.example.com/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure RDPGW [Section titled “Configure RDPGW”](#configure-rdpgw) `rdpgw.yaml` (adjust to your specific requirements): ```yaml Server: Authentication: - openid Tls: disable GatewayAddress: https://rd.example.com Port: 80 # list of acceptable desktop hosts to connect to Hosts: - unraid-vm.local:3389 - 192.168.100.14:3389 HostSelection: unsigned SessionKey: 32-characters-long SessionEncryptionKey: 32-characters-long SessionStore: cookie # Open ID Connect specific settings OpenId: ProviderUrl: https://id.example.com ClientId: ClientSecret: Caps: SmartCardAuth: false # required for openid connect TokenAuth: true IdleTimeout: 0 EnablePrinter: true EnablePort: true EnablePnp: true EnableDrive: true EnableClipboard: true Client: UsernameTemplate: '{{ username }}' SplitUserDomain: false Security: PAATokenSigningKey: 32-characters-long PAATokenEncryptionKey: 32-characters-long UserTokenEncryptionKey: 32-characters-long EnableUserToken: false VerifyClientIp: false ``` ## Configure Caddy [Section titled “Configure Caddy”](#configure-caddy) Then set up your Caddy proxy with caddy-security and Pocket ID by following the [Pocket ID documentation](/docs/guides/proxy-services#caddy). Note You need two different OIDC clients in Pocket ID: one for caddy-security and one for RDPGW. For caddy-security, the callback URL looks like `https://example.com/auth/oauth2/generic/authorization-code-callback`, and for RDPGW it’s `https://rd.example.com/callback`. The `/auth/oauth2/generic/` route is handled by caddy-security, not RDPGW. RDPGW handles `rd.example.com/connect?host=` and then `rd.example.com/callback`. ```ini oauth identity provider generic { delay_start 3 realm generic driver generic client_id your-client-id-from-pocket-id-for-caddy-security client_secret your-client-secret-from-pocket-id-for-caddy-security scopes openid email profile base_auth_url https://id.example.com metadata_url https://id.example.com/.well-known/openid-configuration } transform user { match role user ui link "Pocket-ID" https://id.example.com/ target_blank icon "las la-id-card" ui link "RDPGW Unraid-vm" https://rd.example.com/connect?host=unraid-vm.local%3A3389 target_blank icon "las la-desktop" ui link "RDPGW My-PC" https://rd.example.com/connect?host=192.168.100.14%3A3389 target_blank icon "las la-desktop" } example.com { handle / { redir / /auth } handle /login* { redir * /auth/login } handle /auth* { authenticate with myportal } respond * "Forbidden" 403 { close } } rd.example.com { route { @ws { header Connection *Upgrade* header Upgrade websocket } reverse_proxy http://rdpgw { # Allow non-standard HTTP methods used by RDPGW header_up X-HTTP-Method-Override {http.method} header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_host} header_up X-Forwarded-Proto {scheme} header_up X-Forwarded-Host {host} transport http { versions 1.1 } } } } id.example.com { route { reverse_proxy http://pocket-id { header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_host} header_up X-Forwarded-Proto {scheme} header_up X-Forwarded-Host {host} } } route /caddy-security/* { authenticate with myportal } } ``` # Readeck > Sign in to the Readeck read-it-later app with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Readeck` and add the callback URL `https://readeck.example.com/login/oidc`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Readeck [Section titled “Configure Readeck”](#configure-readeck) Add the following to your Docker Compose file or `.env` file for Readeck. You usually need to give the Pocket ID URL without a trailing slash. Example directly in `compose.yaml`: ```yaml environment: READECK_AUTH_OIDC_PROVIDERS_1_NAME: PocketID READECK_AUTH_OIDC_PROVIDERS_1_URL: https://id.example.com READECK_AUTH_OIDC_PROVIDERS_1_CLIENT_ID: READECK_AUTH_OIDC_PROVIDERS_1_CLIENT_SECRET: ``` Example using an `.env` file: ```ini READECK_AUTH_OIDC_PROVIDERS_1_NAME=PocketID READECK_AUTH_OIDC_PROVIDERS_1_URL=https://id.example.com READECK_AUTH_OIDC_PROVIDERS_1_CLIENT_ID= READECK_AUTH_OIDC_PROVIDERS_1_CLIENT_SECRET= ``` For advanced setups like group mapping or custom claims, refer to the [official Readeck documentation](https://readeck.org/en/docs/external-auth). # ReadMeABook > Sign in to ReadMeABook with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `ReadMeABook` and add the callback URL `https://readmeabook.example.com/api/auth/oidc/callback`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure ReadMeABook [Section titled “Configure ReadMeABook”](#configure-readmeabook) Fill in the OIDC settings in ReadMeABook: | Field | Description | Example | | ------------- | ----------------------------------------- | --------------------------------------------------------- | | Provider Name | Display name | `Pocket ID` | | Issuer URL | The **OIDC Discovery URL** from Pocket ID | `https://id.example.com/.well-known/openid-configuration` | | Client ID | The **Client ID** from Pocket ID | `` | | Client Secret | The **Client secret** from Pocket ID | `` | # RomM > Sign in to the RomM game library with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `RomM` and add the callback URL `https://romm.example.com/api/oauth/openid`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure RomM [Section titled “Configure RomM”](#configure-romm) 1. Set the following RomM environment variables: * `OIDC_ENABLED`: Set to `true` to enable OIDC authentication. * `OIDC_PROVIDER`: The lowercase name of the provider (`pocketid`). * `OIDC_CLIENT_ID`: The **Client ID** from Pocket ID. * `OIDC_CLIENT_SECRET`: The **Client secret** from Pocket ID. * `OIDC_REDIRECT_URI`: The callback URL configured in Pocket ID, in the format `https://romm.example.com/api/oauth/openid`. * `OIDC_SERVER_APPLICATION_URL`: The authorization URL for your Pocket ID instance, for example `https://id.example.com`. 2. Set up your email address in RomM. This email has to match your user email in Pocket ID. # Seafile > Sign in to Seafile Community Edition with Pocket ID. Replace `seafile.example.com` with the URL of your Seafile instance and `id.example.com` with the URL of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Seafile` and add the callback URL `https://seafile.example.com/oauth/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL**, the **Token URL** and the **Userinfo URL**. The client secret is only shown once. 4. On the client’s **General** tab, set **Client Launch URL** to `https://seafile.example.com`, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Seafile [Section titled “Configure Seafile”](#configure-seafile) Set the following variables in your `seahub_settings.py` file, which is normally located at `/opt/seafile/conf/seahub_settings.py` on your Seafile server: ```python ENABLE_OAUTH = True OAUTH_CREATE_UNKNOWN_USER = True OAUTH_ACTIVATE_USER_AFTER_CREATION = True # Only set this to True if you are NOT using HTTPS OAUTH_ENABLE_INSECURE_TRANSPORT = False # ---- Pocket ID client credentials ---- OAUTH_CLIENT_ID = "" OAUTH_CLIENT_SECRET = "" # ---- Redirect URL (must match the Pocket ID callback URL) ---- OAUTH_REDIRECT_URL = "https://seafile.example.com/oauth/callback" # ---- Pocket ID OIDC endpoints ---- OAUTH_PROVIDER = "pocket-id" OAUTH_PROVIDER_DOMAIN = "pocket-id" # <= required for Seafile < 11.0 compatibility OAUTH_AUTHORIZATION_URL = "https://id.example.com/authorize" # Authorization URL from Pocket ID OAUTH_TOKEN_URL = "https://id.example.com/api/oidc/token" # Token URL from Pocket ID OAUTH_USER_INFO_URL = "https://id.example.com/api/oidc/userinfo" # Userinfo URL from Pocket ID # ---- OIDC Scopes ---- OAUTH_SCOPE = [ "openid", "profile", "email" ] # ---- Attribute Mapping ---- OAUTH_ATTRIBUTE_MAP = { "sub": (True, "uid"), # required unique identifier "name": (False, "name"), "email": (False, "contact_email"), } # Force Seafile desktop & mobile clients to redirect to web browser for SSO authentication CLIENT_SSO_VIA_LOCAL_BROWSER = True ``` ## Match existing local users to OIDC login [Section titled “Match existing local users to OIDC login”](#match-existing-local-users-to-oidc-login) When OIDC is configured in Seafile, users with an existing local account who sign in get a brand new account. Seafile doesn’t automatically match the user to their existing local Seafile account. Automatic user matching is only available for LDAP accounts. This appears to be a deliberate design decision rather than a feature that isn’t implemented yet. This can cause issues if the existing local account has the **User ID** set to an email address, but the **Contact Email** is blank. The OIDC login creates a new account with `LONG_GUID@auth.local` as the **User ID** and the email address as the **Contact Email**. The original account then can’t sign in because its **User ID** clashes with the new account’s **Contact Email**. An administrator needs to resolve this. To match OIDC logins to existing local accounts, make manual changes to the Seafile databases with the following steps. ### Get the Seafile user ID [Section titled “Get the Seafile user ID”](#get-the-seafile-user-id) 1. To get the **User ID** (email) of a user, sign in to Seafile as an admin, click the user photo at the top right and click **System Admin**. 2. Click **Users**, then click the name of the user you want to enable for OIDC. Copy the **User ID**. ### Get the Pocket ID user sub [Section titled “Get the Pocket ID user sub”](#get-the-pocket-id-user-sub) 1. Sign in to Pocket ID as an admin. 2. Open **Administration → OIDC Clients** and open the client you created for Seafile. 3. Click **OIDC Data Preview** at the top of the client’s page. 4. Select the correct user, then copy the value of `sub`. ### Match the user in the MariaDB database [Section titled “Match the user in the MariaDB database”](#match-the-user-in-the-mariadb-database) Connect to the command line of your Seafile database server or container and run the following commands (the first command requires the MariaDB root password): ```bash mysql -u root -p # Connect to ccnet_db database MariaDB [(none)]> use ccnet_db; # Check the User ID/email and password of the local account you want to match MariaDB [ccnet_db]> select email,left(passwd,25) from EmailUser where email = 'joe@example.com'; +-------------------------+---------------------------+ | email | left(passwd,25) | +-------------------------+---------------------------+ | joe@example.com | PBKDF2SHA256$10000$53a6a8 | +-------------------------+---------------------------+ # Blank the password MariaDB [ccnet_db]> update EmailUser set passwd = '!' where email = 'joe@example.com'; # The password command should now show a blank password MariaDB [ccnet_db]> select email,left(passwd,25) from EmailUser where email = 'joe@example.com'; +-------------------------+-----------------+ | email | left(passwd,25) | +-------------------------+-----------------+ | joe@example.com | ! | +-------------------------+-----------------+ # Connect to the seahub_db database MariaDB [ccnet_db]> use seahub_db; # Add the email, provider (the pocket-id provider configured earlier) and sub from Pocket ID to the social_auth_usersocialauth table MariaDB [seahub_db]> insert into `social_auth_usersocialauth` (`username`, `provider`, `uid`, `extra_data`) values ('joe@example.com', 'pocket-id', '5942c94c-1b20-509d-964f-dc95835d3484', ''); # Check the command has worked MariaDB [seahub_db]> select * from social_auth_usersocialauth; +----+-------------------------+-----------+--------------------------------------+------------+ | id | username | provider | uid | extra_data | +----+-------------------------+-----------+--------------------------------------+------------+ | 6 | joe@example.com | pocket-id | 5942c94c-1b20-509d-964f-dc95835d3484 | | +----+-------------------------+-----------+--------------------------------------+------------+ ``` When `joe@example.com` now signs in to Seafile with Pocket ID, he sees his existing account instead of getting a new one. # Semaphore UI > Sign in to Semaphore UI with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Semaphore UI` and add the callback URL `https://semaphore.example.com/api/auth/oidc/pocketid/redirect/`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Semaphore UI [Section titled “Configure Semaphore UI”](#configure-semaphore-ui) Add the following to your `config.json` file for Semaphore UI: ```json "oidc_providers": { "pocketid": { "display_name": "Sign in with Pocket ID", "provider_url": "https://id.example.com", "client_id": "", "client_secret": "", "redirect_url": "https://semaphore.example.com/api/auth/oidc/pocketid/redirect/", "scopes": [ "openid", "profile", "email" ], "username_claim": "email", "name_claim": "given_name" } } ``` Semaphore UI versions after 2.14 support a Docker environment variable for this. A single environment variable, `SEMAPHORE_OIDC_PROVIDERS`, lets you configure providers using a JSON string matching the `oidc_providers` structure. ```yaml SEMAPHORE_OIDC_PROVIDERS: >- { "pocketid": { "display_name":"Sign in with Pocket ID", "provider_url":"https://id.example.com", "client_id":"", "client_secret":"", "redirect_url":"https://semaphore.example.com/api/auth/oidc/pocketid/redirect/", "scopes": [ "openid", "profile", "email" ], "username_claim":"email", "name_claim":"given_name" } } ``` # SonarQube > Sign in to the SonarQube code analysis platform with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [SonarQube Community](https://www.sonarsource.com/open-source-editions/sonarqube-community-edition/) * [sonar-auth-oidc](https://github.com/sonar-auth-oidc/sonar-auth-oidc/releases/tag/v3.0.0) plugin v3.0.0 or later * HTTPS connection to your SonarQube instance ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `SonarQube` and add the callback URL `https://sonarqube.example.com/oauth2/callback/oidc`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure SonarQube [Section titled “Configure SonarQube”](#configure-sonarqube) 1. Download [sonar-auth-oidc](https://github.com/sonar-auth-oidc/sonar-auth-oidc/releases/tag/v3.0.0) v3.0.0 or later and copy it into the SonarQube `plugins` directory, usually `/opt/sonarqube/extensions/plugins`. 2. Restart SonarQube. 3. In SonarQube, open **Administration → Configuration → Security** and set the following parameters: * **Enabled**: checked * **Issuer URI**: `https://id.example.com` (the **OIDC Discovery URL** from Pocket ID without `/.well-known/openid-configuration`) * **Client ID**: the **Client ID** from Pocket ID * **Client secret**: the **Client secret** from Pocket ID * **Scopes**: `openid email profile groups` * **Allow users to sign-up**: checked (optional but recommended) * **Login generation strategy**: `Email` ## Control admin access with groups [Section titled “Control admin access with groups”](#control-admin-access-with-groups) To control **admin** access to SonarQube with Pocket ID groups: 1. In Pocket ID, open **Administration → User Groups** and click **Add Group** to create the group. 2. On the group’s page, add a custom claim under **Custom Claims** that matches the SonarQube admin group. The value must be a JSON array. * **Key**: `sonargroups` * **Value**: `["sonar-administrators"]` 3. In SonarQube, open **Administration → Configuration → Security** and set: * **Synchronize groups**: checked * **Groups claim name**: `sonargroups` SonarQube then automatically adds the members of the Pocket ID group to the SonarQube `sonar-administrators` group. ## Additional information [Section titled “Additional information”](#additional-information) More information about [sonar-auth-oidc](https://github.com/sonar-auth-oidc/sonar-auth-oidc/releases/tag/v3.0.0) can be found in its [configuration documentation](https://github.com/sonar-auth-oidc/sonar-auth-oidc?tab=readme-ov-file#configuration). With Pocket ID **Custom Claims**, you can manage SonarQube groups entirely from Pocket ID. # Sonarr > Sign in to the Sonarr dashboard with Pocket ID. Note OIDC support was recently added to Sonarr v5, however it may have some issues as it is still in beta. Check the announcement on the [Sonarr forums](https://forums.sonarr.tv/t/sonarr-v5-beta/41099) for more information. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Sonarr` and add the callback URL `https://sonarr.example.com/signin-oidc`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, turn on **PKCE**, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Sonarr [Section titled “Configure Sonarr”](#configure-sonarr) Note OIDC authentication in Sonarr is limited to a **single user** and `OidcUserIdentifier` is required to allow that single user to authenticate with the matching email address or subject identifier. For more information on configuring Sonarr, see the [Sonarr docs](https://wiki.servarr.com/sonarr/settings#host). ### Via the web interface [Section titled “Via the web interface”](#via-the-web-interface) 1. Log in to Sonarr 2. Go to **Settings → General** and enable **Show Advanced**. 3. Under **Security**, fill in the following fields: | Field | Value | | ----------------------- | ----------------------------------------------------------------------- | | Authentication | `OIDC` | | Authentication Required | `Enabled` | | OIDC Authority | `https://id.example.com` | | OIDC Client ID | The **Client ID** from Pocket ID | | OIDC Client Secret | The **Client secret** from Pocket ID | | OIDC User | The user’s **Verified email** from Pocket ID | | OIDC Scopes | `openid email profile` | | Trusted Networks | The IP address of your reverse proxy (e.g. Caddy, Nginx, Traefik, etc.) | 4. Click on **Save Changes** and restart Sonarr. 5. Click on Login and you will be redirected to Pocket ID for authentication. ### Via the config file [Section titled “Via the config file”](#via-the-config-file) 1. Stop Sonarr. 2. Fill in the required fields in the `config.xml` file (the file location may vary depending on your setup. For more information, check the [Sonarr Appdata Directory](https://wiki.servarr.com/sonarr/appdata-directory)). config.xml ```xml Oidc Enabled https://id.example.com client-id client-secret verified-email@example.com trusted-ip-address ``` 3. Restart Sonarr. 4. Click on Login and you will be redirected to Pocket ID for authentication. Note The User Identifier (`OidcUserIdentifier`) can be changed for the subject identifier (`sub`) of the user from Pocket ID. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) * Check that the Trusted Networks is set correctly in Sonarr, otherwise the login will fail. * Check that Allowed Hosts is set correctly in Sonarr * Check that the email is verified in Pocket ID. Danger If for some reason you can’t log in, you’ll need to manually modify the `config.xml` file, and change the `AuthenticationMethod` back to `Forms` to disable OIDC login. # Synology > Sign in to Synology DSM with Pocket ID. Replace `synology.example.com` with the URL of your Synology instance and `id.example.com` with the URL of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Synology` and add the callback URL `https://synology.example.com/`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Synology [Section titled “Configure Synology”](#configure-synology) 1. Open the Synology DSM web interface and open **Control Panel**. 2. Choose **Domain/LDAP** on the left side, then choose the **SSO Client** tab at the top. 3. Below the **Services** heading, check **Enable OpenID Connect SSO service**. 4. Click **OpenID Connect SSO Settings** to open the configuration dialog. 5. Set **Profile** to `OIDC`. 6. Set **Account type** to `Domain/LDAP/local`. 7. Set **Name** to `PocketID`. 8. Paste the **OIDC Discovery URL** from Pocket ID into the **Well-known URL** field. 9. Paste the **Client ID** from Pocket ID into the **Application ID** field. 10. Paste the **Client secret** from Pocket ID into the **Application secret** field. 11. Set **Redirect URL** to `https://synology.example.com`. 12. Set **Authorization scope** to `openid email profile`. 13. Set **Username claim** to `preferred_username`. This uses the user’s username instead of the email. If the Pocket ID username matches the local Synology DSM account name, the user signs in as the existing user. 14. Click **Save**. 15. Click **Apply** on the **Control Panel** page. 16. Sign out and sign back in to test it. The login page now has an **SSO Authentication** tab that lets you **Continue with PocketID**. # Talos > Sign in to Kubernetes on Talos Linux with Pocket ID. Talos is a lightweight, API-driven, full-stack Kubernetes system. As with any Kubernetes server, you can set it up to authenticate users with OIDC. This guide configures Talos to use Pocket ID as the authentication and authorization server. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Talos` and add the callback URL `http://localhost:8000`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Talos [Section titled “Configure Talos”](#configure-talos) Modify the `cluster.apiServer` block to include the following: ```diff cluster: apiServer: image: registry.k8s.io/kube-apiserver:v1.33.1 # The container image used in the API server manifest. extraArgs: oidc-issuer-url: https://id.example.com oidc-client-id: oidc-username-claim: sub oidc-groups-claim: groups oidc-groups-prefix: "oidc:" ``` Create a cluster role binding that links the admin group you want to use to Kubernetes. In the following example, there is a group called `kubernetes` in Pocket ID that the user is assigned to. ```yaml # filename=crb.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: cluster-admins-from-pass-keys roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: oidc:kubernetes ``` Apply it: ```shell kubectl apply -f crb.yaml ``` ### Modify the kubeconfig file [Section titled “Modify the kubeconfig file”](#modify-the-kubeconfig-file) Install the command line tool [kubelogin](https://github.com/int128/kubelogin). Refer to its GitHub repository for instructions for your system. Run the following command to generate a config and validate that the token works: ```shell kubectl oidc-login setup \ --oidc-issuer-url=https://id.example.com \ --oidc-client-id= \ --oidc-client-secret= \ --oidc-extra-scope=groups,email,name,sub,email_verified ``` Make sure that your email is verified, as [Kubernetes requires this](https://github.com/kubernetes/kubernetes/blob/77bd3f89fbc389d5dfebbed880e08a1e4949312c/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/oidc.go#L833-L847) when working with OIDC. You *should* get a response similar to this: ```json { "aud": "a60960a8-c856-43b7-add7-50d83bf7eeab", "email": "username@domain.com", "email_verified": true, "exp": 1749867571, "groups": ["kubernetes"], "iat": 1749863971, "iss": "https://id.example.com", "nonce": "sLY0SUaiLxe9JDfUpNEsBDbhKceOB-T1zxxRYJPQbvk", "sub": "643c3fba-370a-4738-92a6-9ergec96cd99" } ``` Create a new user in your `~/.kube/config` file: ```yaml - name: pocket-id user: exec: apiVersion: client.authentication.k8s.io/v1beta1 args: - oidc-login - get-token - --oidc-issuer-url= - --oidc-client-id= - --oidc-client-secret= - --oidc-extra-scope=groups - --oidc-extra-scope=email - --oidc-extra-scope=name ``` Then update your current context to use this user: ```diff - context: cluster: testing namespace: default user: admin@testng user: pocket-id name: testing ``` ## Further reading [Section titled “Further reading”](#further-reading) * [Kubernetes OIDC](https://kubernetes.io/docs/reference/access-authn-authz/authentication/) * [More in-depth documentation and possible errors](https://documentation.breadnet.co.uk/kubernetes/oidc/talos-oidc-pocket-id/) # Tandoor Recipes > Sign in to the Tandoor Recipes manager with Pocket ID. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Tandoor Recipes` and add the callback URL `https://tandoor.example.com/accounts/oidc/pocket-id/login/callback/`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Tandoor Recipes [Section titled “Configure Tandoor Recipes”](#configure-tandoor-recipes) 1. Add the following environment variables to your Tandoor setup, for example in the `.env` file. In `SOCIALACCOUNT_PROVIDERS`, replace `` and `` with the **Client ID** and the **Client secret** from Pocket ID, and `id.example.com` with your Pocket ID domain. ```ini SOCIAL_PROVIDERS=allauth.socialaccount.providers.openid_connect SOCIALACCOUNT_PROVIDERS='{"openid_connect":{"APPS":[{"provider_id":"pocket-id","name":"Pocket ID","client_id":"","secret":"","settings":{"server_url":"https://id.example.com/.well-known/openid-configuration"}}]}}' ``` 2. Restart Tandoor. The login page now has an option to sign in with Pocket ID. You can also link existing accounts with Pocket ID in your Tandoor profile settings. # Technitium DNS > Sign in to Technitium DNS Server with Pocket ID. Technitium DNS Server supports external OIDC-based single sign-on. This guide configures Pocket ID as the SSO provider for Technitium DNS. Replace `dns.example.com` with the URL of your Technitium DNS web interface and `id.example.com` with the URL of your Pocket ID instance. ## Requirements [Section titled “Requirements”](#requirements) * Technitium DNS Server 15.2 or later Technitium DNS SSO has the following characteristics: * It uses a **confidential client** (Authorization Code flow with client secret). The Pocket ID client must **not** be a public client. * **PKCE is not required**, because Technitium handles the code exchange server-side. * SSO login is per-server, not per-user. Once configured, a “Login with SSO” button appears on the login page. * Group membership in Pocket ID is mapped to **local Technitium groups** (`Administrators`, `DNS Administrators`, `DHCP Administrators`). Users in no mapped group can’t log in. * New users can be **auto-provisioned** on first SSO login if they belong to a mapped group. * The `groups` scope must be included so Technitium receives group membership in the token. ## Create groups in Pocket ID [Section titled “Create groups in Pocket ID”](#create-groups-in-pocket-id) In Pocket ID, open **Administration → User Groups** and click **Add Group** to create the following groups. Use these exact values for **Name**, because they’re referenced in the Technitium group map. | Group name | Maps to Technitium group | | ------------------------ | -------------------------------------------- | | `technitium_admins` | `Administrators` (full access) | | `technitium_dns_admins` | `DNS Administrators` (DNS management only) | | `technitium_dhcp_admins` | `DHCP Administrators` (DHCP management only) | Add users to whichever group reflects their role. Users not in any of these groups are denied access. > No custom claims are needed on these groups. Technitium reads group names from the standard `groups` claim. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Technitium DNS` and add the callback URL `https://dns.example.com/sso/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select `technitium_admins`, `technitium_dns_admins` and `technitium_dhcp_admins` under **Allowed User Groups**. ## Configure Technitium DNS [Section titled “Configure Technitium DNS”](#configure-technitium-dns) Technitium SSO is server-wide, so there is no per-user setup. 1. Log in to Technitium as an administrator. 2. Go to **Administration → SSO Providers**. 3. Enable SSO and fill in the following fields: | Field | Value | | ---------------------------------- | --------------------------------------------------------- | | Authority | `https://id.example.com` | | Client ID | The **Client ID** from Pocket ID | | Client Secret | The **Client secret** from Pocket ID | | Metadata Address | `https://id.example.com/.well-known/openid-configuration` | | Scopes | `openid profile email groups` | | Allow Signup | Enabled | | Allow Signup Only for Mapped Users | Enabled | 4. Under **Group Map**, add the following entries: | Remote Group (Pocket ID) | Local Group (Technitium) | | ------------------------ | ------------------------ | | `technitium_admins` | `Administrators` | | `technitium_dns_admins` | `DNS Administrators` | | `technitium_dhcp_admins` | `DHCP Administrators` | 5. Save. Technitium restarts its web service to apply the OIDC middleware. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) ### SSO button does not appear on the login page [Section titled “SSO button does not appear on the login page”](#sso-button-does-not-appear-on-the-login-page) SSO is not enabled or the web service did not restart after configuration. Re-open **Administration → SSO Providers** and confirm SSO is enabled and saved. If the setting is correct but the button is still missing, reload the page or clear the browser cache. ### “Access denied” after authenticating with Pocket ID [Section titled ““Access denied” after authenticating with Pocket ID”](#access-denied-after-authenticating-with-pocket-id) The user is not a member of any mapped group in Pocket ID. Add the user to one of the three Technitium groups (`technitium_admins`, `technitium_dns_admins`, or `technitium_dhcp_admins`). Also verify that **Allowed User Groups** on the client’s **Access** tab in Pocket ID contains those three groups. ### Authentication fails silently after redirect [Section titled “Authentication fails silently after redirect”](#authentication-fails-silently-after-redirect) The client secret in Pocket ID does not match the one configured in Technitium. Add a new secret on the client’s **Credentials** tab in Pocket ID with **Add client secret**, then update the Technitium SSO config with the new value. ### Group mapping has no effect (user logs in but gets wrong permissions) [Section titled “Group mapping has no effect (user logs in but gets wrong permissions)”](#group-mapping-has-no-effect-user-logs-in-but-gets-wrong-permissions) The `groups` scope is missing from the Technitium SSO configuration. Verify that the scopes include `groups`. Also check that the remote group names in the Technitium group map **exactly match** the group names in Pocket ID (case-sensitive). ### Existing local admin account is locked out after enabling SSO [Section titled “Existing local admin account is locked out after enabling SSO”](#existing-local-admin-account-is-locked-out-after-enabling-sso) SSO does not replace local authentication, so both methods remain active. Local accounts can still log in with username and password (plus TOTP if enabled). The SSO button is an additional option, not a replacement. # Termix > Sign in to the Termix server management platform with Pocket ID. Replace `termix.example.com` with the URL of your [Termix](https://termix.site/) instance and `id.example.com` with the URL of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Termix` and add the callback URL `https://termix.example.com/users/oidc/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Issuer URL**, the **Authorization URL**, the **Token URL** and the **Userinfo URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. *(Optional)* To manage Termix admins from Pocket ID, open **Administration → User Groups**, click **Add Group**, create a group named `termix-admin` and add the users that should become admins in Termix. ## Configure Termix [Section titled “Configure Termix”](#configure-termix) You can set this up in the GUI or with environment variables. ### GUI [Section titled “GUI”](#gui) In the GUI, you can configure multiple OIDC clients. 1. Log in to Termix as an administrator. 2. Click your admin username in the bottom-left corner and open the **Admin Settings** interface. 3. Open the **SSO PROVIDERS** tab. 4. Click **Add provider**. 5. Set the following settings: * **Display name**: `Pocket ID` * **Client ID**: the **Client ID** from Pocket ID * **Client Secret**: the **Client secret** from Pocket ID * **Issuer URL**: the **Issuer URL** from Pocket ID * **Authorization URL**: the **Authorization URL** from Pocket ID * **Token URL**: the **Token URL** from Pocket ID * *(Optional)* To configure the admins from Pocket ID: * Add `groups` to the **Scopes** field, so that it becomes `openid email profile groups`. * **Group claim**: `groups` * **Admin group**: `termix-admin` 6. Click **Save Provider**. ### Environment variables [Section titled “Environment variables”](#environment-variables) Set the following environment variables in your `.env` file: ```ini OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= OIDC_ISSUER_URL=https://id.example.com OIDC_AUTHORIZATION_URL=https://id.example.com/authorize OIDC_TOKEN_URL=https://id.example.com/api/oidc/token OIDC_USERINFO_URL=https://id.example.com/api/oidc/userinfo ``` *(Optional)* To configure the admins from Pocket ID, also set: ```ini OIDC_SCOPES=openid email profile groups OIDC_ADMIN_GROUP=termix-admin ``` ## Known issues [Section titled “Known issues”](#known-issues) Be careful with the option **General - Silent OIDC Login by Default**, because it can send your application into an infinite loop. # tududi > Sign in to the tududi task manager with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [tududi](https://github.com/chrisvel/tududi/releases/tag/v1.1.0) `v1.1.0` or later * Pocket ID on HTTPS, reachable at `https://id.example.com` * tududi server on HTTPS, reachable at `https://tududi.example.com` ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `tududi` and add the callback URL `https://tududi.example.com/api/oidc/callback/pocketid`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, set **Client Launch URL** to `https://tududi.example.com`, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure tududi [Section titled “Configure tududi”](#configure-tududi) This is the minimal configuration needed to set up Pocket ID with tududi, taken from [the tududi OIDC SSO docs](https://github.com/chrisvel/tududi/blob/main/docs/10-oidc-sso.md#pocketid). 1. Add the following lines to your environment variables file, replacing `` and `` with the **Client ID** and the **Client secret** from Pocket ID: ```ini OIDC_ENABLED=true OIDC_PROVIDER_NAME=PocketID OIDC_PROVIDER_SLUG=pocketid OIDC_ISSUER_URL=https://id.example.com OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= OIDC_SCOPE=openid profile email OIDC_AUTO_PROVISION=true # when tududi is behind a reverse proxy: TUDUDI_TRUST_PROXY=true # required for proper session handling after OIDC login ``` 2. Save and restart the tududi Docker Compose stack or app. # Unraid > Sign in to your Unraid server with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * Unraid 7.2.0 or later More information about the Unraid OIDC configuration can be found in the [Unraid documentation](https://docs.unraid.net/API/oidc-provider-setup/). ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Unraid` and add the callback URL `http://unraid.example.com/graphql/api/auth/oidc/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Unraid [Section titled “Configure Unraid”](#configure-unraid) 1. In Unraid, open **Settings → Management Access → API → OIDC**. 2. Click the plus button on the far right of the **OIDC Providers** section. 3. Fill in the required fields: * **Provider ID**: a unique ID for your provider, for example `pocket-id`. * **Provider Name**: the display name for the provider, for example `Pocket ID`. * **Client ID**: the **Client ID** from Pocket ID. * **Client Secret**: the **Client secret** from Pocket ID. * **Issuer URL**: `https://id.example.com`, **without a trailing slash**. 4. Set the authorization mode. The quickest option is **Simple Authorization**. 5. *(Optional)* Customize the button style. 6. Click **Apply** at the bottom of the page and sign in with Pocket ID to test it. # Vaultwarden > Sign in to the Vaultwarden password manager with Pocket ID. Replace `vaultwarden.example.com` and `id.example.com` with your own server names. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Vaultwarden` and add the callback URL `https://vaultwarden.example.com/identity/connect/oidc-signin`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, turn on **PKCE**, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Vaultwarden [Section titled “Configure Vaultwarden”](#configure-vaultwarden) Set the following variables in your Vaultwarden environment file. Replace `` and `` with the **Client ID** and the **Client secret** from Pocket ID. ```ini SSO_ENABLED=true SSO_SIGNUPS_MATCH_EMAIL=true SSO_ALLOW_UNKNOWN_EMAIL_VERIFICATION=true #Only keep this on true if you are willing to accept the risks: https://github.com/dani-garcia/vaultwarden/wiki/Enabling-SSO-support-using-OpenId-Connect#on-sso_allow_unknown_email_verification SSO_PKCE=true #Only set this to true if you enabled PKCE (recommended) in Pocket ID otherwise set it to false SSO_SCOPES=email profile groups offline_access SSO_CLIENT_ID= SSO_CLIENT_SECRET= SSO_AUTHORITY=https://id.example.com #Replace with your pocket-id server. ``` ## Notes [Section titled “Notes”](#notes) If you store your passkey in Vaultwarden, you need a secondary passkey outside of Vaultwarden (iCloud, browser, etc.) to sign in with SSO. This is recommended anyway in case you ever get locked out of Vaultwarden. # Vercel > Sign in to Vercel with Pocket ID and provision users with Directory Sync. This guide connects a [Vercel](https://vercel.com/) team to Pocket ID for both **Single Sign-On (SSO)** via OIDC and **Directory Sync (SCIM)**. Once configured, users sign in to Vercel through Pocket ID and are automatically provisioned into your Vercel team based on their Pocket ID group membership. Note These features are only available on certain Vercel plans: * **Single Sign-On** requires the **Pro** plan (as a paid add-on) or the **Enterprise** plan. * **Directory Sync** is available on the **Enterprise** plan only. The following placeholders are used below. Replace them with your own values: | Placeholder | Replace with | | ---------------- | -------------------------------------------------- | | `id.example.com` | The URL of your Pocket ID instance | | `` | Your Vercel team slug, found in your team settings | Note Your Pocket ID instance must be publicly reachable over HTTPS. Vercel connects to it for OIDC discovery and token exchange, and Pocket ID connects to Vercel for SCIM provisioning. ## Create groups in Pocket ID [Section titled “Create groups in Pocket ID”](#create-groups-in-pocket-id) These groups control who can sign in and which Vercel role each user receives. In Pocket ID, open **Administration → User Groups** and click **Add Group** to create two groups: 1. **Vercel Users** grants standard access to the Vercel team. * **Friendly Name**: `Vercel Users` * **Name**: `vercel-user` * Later, when configuring Directory Sync, you map this group to a Member or Developer role on Vercel. 2. **Vercel Admins** grants admin access to the Vercel team. * **Friendly Name**: `Vercel Admins` * **Name**: `vercel-admin` * Later, when configuring Directory Sync, you map this group to an Owner role on Vercel. Add your own Pocket ID account to both groups so you can test the connection. ## Start the SSO setup in Vercel [Section titled “Start the SSO setup in Vercel”](#start-the-sso-setup-in-vercel) 1. Open your Vercel team’s settings and start configuring **Single Sign-On (SAML)**. 2. Select **Custom OIDC** as the provider type. 3. Set the provider name to `Pocket ID`. 4. Copy the **Login redirect URL** shown by Vercel. It looks like `https://auth.vercel.com/sso/oidc//callback`. You need it in the next step. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Vercel` and add the **Login redirect URL** you copied from Vercel as the callback URL. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, set **Client Launch URL** to `https://vercel.com/login?saml=`, turn on **PKCE** and save. The launch URL makes the Vercel tile in Pocket ID’s **My Apps** open Vercel with your team slug pre-filled. 5. On the client’s **Access** tab, select the **Vercel Users** group under **Allowed User Groups** so that only members of that group can sign in. ## Finish the SSO setup in Vercel [Section titled “Finish the SSO setup in Vercel”](#finish-the-sso-setup-in-vercel) 1. Set the **Discovery endpoint** to `https://id.example.com/.well-known/openid-configuration`. 2. Enter the **Client ID** and the **Client secret** from Pocket ID. 3. Save the SSO configuration. ### Test SSO [Section titled “Test SSO”](#test-sso) Sign out of Vercel and sign back in through Pocket ID (or use a private browser window). In Pocket ID’s **My Apps** view, the **Vercel** tile takes you straight to Vercel with the team slug pre-filled. ## Configure Directory Sync (SCIM) [Section titled “Configure Directory Sync (SCIM)”](#configure-directory-sync-scim) ### In Vercel [Section titled “In Vercel”](#in-vercel) 1. In your Vercel team’s settings, open **Directory Sync** and select **Custom SCIM**. 2. Set the directory provider to **Pocket ID**. 3. Choose **Bearer Token** authentication, then copy the **SCIM endpoint** (looks like `https://auth.vercel.com/scim/v2.0/`) and the **Bearer token** (looks like `se_xxx`). ### In Pocket ID [Section titled “In Pocket ID”](#in-pocket-id) 1. Open the `Vercel` OIDC client and go to its **SCIM Provisioning** tab. 2. Set **SCIM Endpoint** to the SCIM endpoint from Vercel. 3. Set **SCIM Token** to the bearer token from Vercel. 4. Click **Enable**. ### Back in Vercel [Section titled “Back in Vercel”](#back-in-vercel) 1. Save the Directory Sync configuration. 2. Configure the mapping between your Pocket ID groups (**Vercel Users** and **Vercel Admins**) and the corresponding Vercel team roles or Access Groups. For example, map Vercel Users to the Member or Developer role on Vercel, and Vercel Admins to the Owner role on Vercel. Users who belong to the mapped groups are now provisioned into your Vercel team automatically. Note Directory Sync runs periodically (roughly once an hour). To provision users immediately, click **Sync now** on the **SCIM Provisioning** tab of the `Vercel` client in Pocket ID. Users should appear in Vercel within a few minutes. # Vikunja > Sign in to the Vikunja task manager with Pocket ID. Replace `vikunja.example.com` with the URL of your Vikunja instance and `id.example.com` with the URL of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Vikunja` and add the callback URL `https://vikunja.example.com/auth/openid/pocketid`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Vikunja [Section titled “Configure Vikunja”](#configure-vikunja) You can use either a `config.yml` file or environment variables to configure Vikunja. In both cases, replace `` and `` with the **Client ID** and the **Client secret** from Pocket ID. ### Using config.yml [Section titled “Using config.yml”](#using-configyml) This uses the Vikunja 1.0+ syntax. For the deprecated pre-1.0 syntax, see the [Vikunja OpenID documentation](https://vikunja.io/docs/openid/). 1. Map a config file to your Vikunja container, see [Using a config file with Docker Compose](https://vikunja.io/docs/config-options/#using-a-config-file-with-docker-compose). 2. Add or set the following content in the `config.yml` file: ```yaml auth: openid: enabled: true redirecturl: https://vikunja.example.com/auth/openid/pocketid providers: PocketID: name: PocketID authurl: https://id.example.com clientid: clientsecret: scope: openid profile email forceuserinfo: false # Optional: Set to true to always use UserInfo endpoint instead of ID token claims, defaults to false ``` ### Using environment variables [Section titled “Using environment variables”](#using-environment-variables) ```yaml VIKUNJA_AUTH_OPENID_ENABLED: "true" VIKUNJA_AUTH_OPENID_PROVIDERS_POCKETID_AUTHURL: https://id.example.com VIKUNJA_AUTH_OPENID_PROVIDERS_POCKETID_CLIENTID: VIKUNJA_AUTH_OPENID_PROVIDERS_POCKETID_CLIENTSECRET: VIKUNJA_AUTH_OPENID_PROVIDERS_POCKETID_NAME: PocketID VIKUNJA_AUTH_OPENID_PROVIDERS_POCKETID_SCOPE: "openid profile email" ``` ## Link existing local accounts [Section titled “Link existing local accounts”](#link-existing-local-accounts) Vikunja 1.0+ allows users with existing local accounts to log in with OpenID. This feature links OpenID providers to local user accounts based on matching `email` and `username` attributes. Important security note from the Vikunja documentation When using SSO authentication, Vikunja creates a new SSO user if no matching local user is found. If you misconfigure the matching parameters, this could result in duplicate accounts that prevent logging into the intended local account via SSO until the duplicate SSO user is deleted. Additionally, this feature introduces potential security risks, as it allows third-party providers to authenticate as local users if they can control the username or email claims. Only enable this feature with trusted identity providers. An example `config.yml` could look like this: ```yaml auth: openid: enabled: true redirecturl: https://vikunja.example.com/auth/openid/pocketid providers: PocketID: name: PocketID usernamefallback: true emailfallback: true authurl: https://id.example.com clientid: clientsecret: scope: openid profile email forceuserinfo: false # Optional: Set to true to always use UserInfo endpoint instead of ID token claims, defaults to false ``` # Wallos > Sign in to the Wallos subscription tracker with Pocket ID. Replace `wallos.example.com` with the URL of your [Wallos](https://github.com/ellite/Wallos#readme) instance and `id.example.com` with the URL of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Wallos` and add the callback URL `https://wallos.example.com`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. Under **Show more details**, also copy the **Authorization URL**, the **Token URL** and the **Userinfo URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Wallos [Section titled “Configure Wallos”](#configure-wallos) 1. Open the Wallos admin interface (`/admin.php`) and go to **OIDC Settings**. 2. Fill in the required fields with values from Pocket ID: * **Display Name** of your choice (for example `PocketID`) * **Client ID**: the **Client ID** from Pocket ID * **Client Secret**: the **Client secret** from Pocket ID * **Auth URL**: the **Authorization URL** from Pocket ID * **Token URL**: the **Token URL** from Pocket ID * **User info URL**: the **Userinfo URL** from Pocket ID 3. *(Optional)* Enable automatic user creation. 4. Set **Redirect URL** to `wallos.example.com/index.php`. 5. Turn the OIDC toggle on. 6. Save the settings and sign in with Pocket ID to test it. # Wekan > Sign in to the Wekan kanban board with Pocket ID. ## Requirements [Section titled “Requirements”](#requirements) * [Wekan](https://github.com/wekan/wekan) * HTTPS connection to your Wekan server ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Wekan` and add the callback URL `https://wekan.example.com/_oauth/oidc`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure Wekan [Section titled “Configure Wekan”](#configure-wekan) Use the following environment variables to configure OpenID (Docker shown). Replace `` and `` with the **Client ID** and the **Client secret** from Pocket ID. ```yaml services: ... wekan: ... environment: - OAUTH2_ENABLED=true - OIDC_REDIRECTION_ENABLED=true # for mandatory - OAUTH2_LOGIN_STYLE=popup # or redirect - OAUTH2_CLIENT_ID= - OAUTH2_SECRET= - OAUTH2_SERVER_URL=https://id.example.com - OAUTH2_AUTH_ENDPOINT=/authorize - OAUTH2_USERINFO_ENDPOINT=/api/oidc/userinfo - OAUTH2_TOKEN_ENDPOINT=/api/oidc/token - OAUTH2_ID_MAP=preferred_username - OAUTH2_FULLNAME_MAP=name - OAUTH2_USERNAME_MAP=preferred_username - OAUTH2_EMAIL_MAP=email ... ``` ## Notes [Section titled “Notes”](#notes) Configuration adapted from the [Authentik guide for Wekan](https://docs.goauthentik.io/integrations/services/wekan/#wekan-configuration). Tested and working in Wekan `v7.90`. # wg-access-server > Sign in to the wg-access-server WireGuard VPN server with Pocket ID. wg-access-server supports OIDC out of the box. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `wg-access-server` and add the callback URL `https://wg.example.com/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure wg-access-server [Section titled “Configure wg-access-server”](#configure-wg-access-server) 1. Open the `config.yaml` used by the server. 2. Create an `auth` section with an `oidc` subsection. 3. Enter the values as follows: ```yaml auth: oidc: # Can be anything you like name: Pocket-ID # Should point to the domain you are hosting Pocket-ID on issuer: https://id.example.com # ID and Secret provided by Pocket-ID clientID: clientSecret: # Callback URL you entered in Pocket-ID redirectURL: https://wg.example.com/callback # List of scopes to request claims for. # Must include at least 'openid'. scopes: - openid - profile - email - groups ``` For further reference, consult the [upstream documentation](https://www.freie-netze.org/wg-access-server/4-auth/#configuration). ### Managing privileges [Section titled “Managing privileges”](#managing-privileges) You can map groups of users that are allowed to access wg-access-server and define a group of users with admin privileges. For example, when using [LLDAP](https://github.com/lldap/lldap) as a backend for Pocket ID, all LLDAP administrators (members of the group `lldap_admin`) can also be granted administrative privileges in wg-access-server with this claim mapping: ```yaml auth: oidc: # ... claimMapping: admin: "'lldap_admin' in groups" ``` Note that you need to enable the `groups` scope in the configuration. ### Restricting email domains [Section titled “Restricting email domains”](#restricting-email-domains) wg-access-server can optionally restrict user access to specific email domains: ```yaml auth: oidc: # ... emailDomains: - example.com ``` Note that you need to enable the `email` scope in the configuration. # WordPress > Sign in to any WordPress site with Pocket ID. Replace `my-website.com` with the URL of your WordPress instance and `id.example.com` with the URL of your Pocket ID instance. This guide uses the [OpenID Connect Generic Client WordPress Plugin](https://github.com/oidc-wp/openid-connect-generic). Other plugins should work about the same. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `WordPress` and add the callback URL `https://my-website.com/wp-admin`. 3. Click **Create** and copy the **Client ID**, the **Client secret** and the **OIDC Discovery URL**. The client secret is only shown once. 4. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure WordPress [Section titled “Configure WordPress”](#configure-wordpress) 1. Open the WordPress admin interface and go to **Plugins → Add Plugin**. 2. Search for `OpenID Connect Generic Client` by `Jonathan Daggerhart`, then click **Install** and **Activate**. 3. Go to **Settings → OpenID Connect Client**. 4. At the top, you’ll find a **Quick Setup**. Enter the **OIDC Discovery URL** from Pocket ID and click **Load Configuration**. 5. Fill out the following fields: * **Login Type**: `OpenID connect button on login form`. *Do **NOT** change this until you’ve successfully tested your new OIDC login!* * **Client ID**: the **Client ID** from Pocket ID * **Client Secret**: the **Client secret** from Pocket ID 6. Save your settings. 7. Open a private browser window and make sure the OIDC login works. 8. *(Optional)* Change **Login Type** to `Auto Login - SSO`. ## Troubleshooting [Section titled “Troubleshooting”](#troubleshooting) If you use the *Kadence Security* plugin, make sure `2FA` is disabled. Otherwise the login process redirects you back to your Pocket ID instance and you can’t get into the WordPress admin page. # Yuvomi > Sign in to Yuvomi with Pocket ID. Replace `yuvomi.example.com` with the URL of your Yuvomi instance and `id.example.com` with the URL of your Pocket ID instance. ## Create the client in Pocket ID [Section titled “Create the client in Pocket ID”](#create-the-client-in-pocket-id) 1. In Pocket ID, open **Administration → OIDC Clients** and click **Add OIDC Client**. 2. Enter a name such as `Yuvomi` and add the callback URL `https://yuvomi.example.com/api/v1/auth/oidc/callback`. 3. Click **Create** and copy the **Client ID** and the **Client secret**. The client secret is only shown once. 4. On the client’s **General** tab, turn on **PKCE**, then click **Save**. 5. On the client’s **Access** tab, select the groups that may sign in under **Allowed User Groups**, or choose **All Users**. ## Configure email verification in Pocket ID [Section titled “Configure email verification in Pocket ID”](#configure-email-verification-in-pocket-id) 1. In Pocket ID, open **Administration → Application Configuration → Email**. 2. Enable **Emails verified by default**. 3. Open each user under **Administration → Users** and verify their email address. Pocket ID then sends `email_verified: true` for that user. ## Configure Yuvomi [Section titled “Configure Yuvomi”](#configure-yuvomi) Set the following environment variables in Yuvomi: ```ini OIDC_ISSUER=https://id.example.com OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= OIDC_REDIRECT_URI=https://yuvomi.example.com/api/v1/auth/oidc/callback ``` Replace `` and `` with the **Client ID** and the **Client secret** from Pocket ID. Then restart Yuvomi and sign in with Pocket ID to test it. ## Secure default for email verification [Section titled “Secure default for email verification”](#secure-default-for-email-verification) Keep Yuvomi’s fallback for a missing verification claim disabled: ```ini OIDC_TRUST_EMAIL_WITHOUT_VERIFIED_CLAIM=false ``` This is the secure default. Yuvomi links an existing local account by email only when Pocket ID sends `email_verified: true` and exactly one local account has that email address. Do not set this option to `true` when Pocket ID can provide the claim. The redirect URL must match the callback URL registered in Pocket ID exactly. For the remaining OIDC options, account linking behavior, signup restrictions, and passwordless SSO, see Yuvomi’s [SSO / OpenID Connect documentation](https://github.com/ulsklyc/yuvomi/blob/main/docs/installation.md#sso--openid-connect-optional). # Changelog > Release notes for every Pocket ID version, with the new features, fixes and breaking changes of each release. ## v2.19.1 - 2026-10-22 [Section titled “v2.19.1 - 2026-10-22”](#v2191---2026-10-22) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.19.1) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes) * bump go to v1.27.3, alpine to 3.24.3 and distroless to debian13 ([ec14aa2](https://github.com/pocket-id/pocket-id/commit/ec14aa22af23324f1820adec1e70fb67c5554156) by @kmendell) ### Other [Section titled “Other”](#other) * Bump vite-plus from 1.1.0 to 1.3.0 ([274977c](https://github.com/pocket-id/pocket-id/commit/274977cf733039f280459de46d2de2e596696d2b) by @kmendell) **Full Changelog**: ## v2.19.0 - 2026-10-21 [Section titled “v2.19.0 - 2026-10-21”](#v2190---2026-10-21) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.19.0) ### Features [Section titled “Features”](#features) * add configurable login notification modes ([#1813](https://github.com/pocket-id/pocket-id/pull/1813) by @stonith404) * make my apps searchable and sortable ([9c0c304](https://github.com/pocket-id/pocket-id/commit/9c0c304d59369db8370db96cd629a3394f33e5a7) by @stonith404) * add ability to override SSRF protection with `OUTBOUND_ALLOWED_HOSTS_*` ([3ffe013](https://github.com/pocket-id/pocket-id/commit/3ffe013886a9af9e60090a1ddbf8cb399a55b948) by @stonith404) * use WebAuthn recommended passkey algorithms ([#1841](https://github.com/pocket-id/pocket-id/pull/1841) by @michaelbeaumont) * add ability to force email verification ([#1837](https://github.com/pocket-id/pocket-id/pull/1837) by @stonith404) * add ability to deselect scopes on authorization ([f81d62c](https://github.com/pocket-id/pocket-id/commit/f81d62c16ceba0e0130ff210d663775068f1a0a8) by @stonith404) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-1) * prevent DN collisions from assigning another user’s privileges ([be45b1c](https://github.com/pocket-id/pocket-id/commit/be45b1c9a3df571b8b8caa33c888e31d0f83096e) by @stonith404) * remove distracting tab switch animation ([69065e7](https://github.com/pocket-id/pocket-id/commit/69065e7cf009b4ac99b5fbc6a11dd6d919560f0a) by @stonith404) * export from SQLite fails to import into Postgres because of mismatched schemas ([8ab3dd4](https://github.com/pocket-id/pocket-id/commit/8ab3dd437b3c43371d542ef90f4ec32602f34c42) by @stonith404) * limit upload size for profile pictures and application images ([#1819](https://github.com/pocket-id/pocket-id/pull/1819) by @IonBazan) * prevent email enumeration via one-time access email request ([ade5520](https://github.com/pocket-id/pocket-id/commit/ade55206b865042d038e7c5e314eccccdded7197) by @stonith404) * rate limit updating the own account to slow down user enumeration ([226648c](https://github.com/pocket-id/pocket-id/commit/226648c7b2ced55d3084366a6297472942b414db) by @stonith404) * reject cross-origin state-changing requests ([d31e3e1](https://github.com/pocket-id/pocket-id/commit/d31e3e12866d9c404d6c8323171fe01d80eb83dd) by @stonith404) * limit LDAP profile picture downloads to 2 MB ([d8ca4b6](https://github.com/pocket-id/pocket-id/commit/d8ca4b67525f3d656bd5a917af52d5849bd23d94) by @stonith404) * remove unused oidc client `/meta` endpoint ([a58ccea](https://github.com/pocket-id/pocket-id/commit/a58ccea6cec3aaa17a643921c5df461fc0886320) by @stonith404) * only return minimal client metadata for public interaction endpoint ([03fc844](https://github.com/pocket-id/pocket-id/commit/03fc844d055437e1391b29cdda0b28c8c94e6bdb) by @stonith404) * prefix audit log event translation keys to separate them from UI strings ([c7a7bce](https://github.com/pocket-id/pocket-id/commit/c7a7bce426b7abae55613c526ca6dd43fe6b1bdc) by @stonith404) * push group removals made on the user page to SCIM ([#1830](https://github.com/pocket-id/pocket-id/pull/1830) by @jayhemnani9910) * push group removals if user gets deleted to SCIM ([d7f58e5](https://github.com/pocket-id/pocket-id/commit/d7f58e5a33f0df528a0df59c63d86e41ffd2578f) by @stonith404) * fallback to username if chars in name are not supported for avatars ([e2cacac](https://github.com/pocket-id/pocket-id/commit/e2cacac193968e4fd49b19f5cc62b0cfd9bbfef8) by @stonith404) * keep integer custom claim values exact in ID tokens and userinfo ([#1829](https://github.com/pocket-id/pocket-id/pull/1829) by @jayhemnani9910) * push users disabled by the LDAP sync to SCIM ([#1834](https://github.com/pocket-id/pocket-id/pull/1834) by @jayhemnani9910) * skip LDAP users without an email instead of failing the whole sync ([#1835](https://github.com/pocket-id/pocket-id/pull/1835) by @jayhemnani9910) * send the API key expiration email again after a renewal ([#1847](https://github.com/pocket-id/pocket-id/pull/1847) by @jayhemnani9910) * find user groups by their friendly name in the admin search ([#1854](https://github.com/pocket-id/pocket-id/pull/1854) by @choksi2212) * keep login notification and email verification settings on upgrade ([6b9aba1](https://github.com/pocket-id/pocket-id/commit/6b9aba173572aa1ea79a6157e77da3169a3754d8) by @stonith404) ### Documentation [Section titled “Documentation”](#documentation) * update README screenshots ([ed45102](https://github.com/pocket-id/pocket-id/commit/ed45102da12110c03ceebb3c9730a68d422f8cfb) by @stonith404) ### Other [Section titled “Other”](#other-1) * update AAGUIDs ([#1811](https://github.com/pocket-id/pocket-id/pull/1811) by @pocket-id-bot\[bot]) * Bump sharp from 0.35.4 to 0.35.5 ([#1818](https://github.com/pocket-id/pocket-id/pull/1818) by @dependabot\[bot]) * Bump source-map-js from 1.2.1 to 1.2.2 ([#1817](https://github.com/pocket-id/pocket-id/pull/1817) by @dependabot\[bot]) * Bump the “all-dependencies” group with 4 updates across multiple ecosystems ([#1826](https://github.com/pocket-id/pocket-id/pull/1826) by @dependabot\[bot]) * resolve golangci-lint failures ([1bd6f00](https://github.com/pocket-id/pocket-id/commit/1bd6f006c8b92092641a6f1960e966c3cb6b999a) by @stonith404) * authorize API routes with per-endpoint scopes ([#1823](https://github.com/pocket-id/pocket-id/pull/1823) by @stonith404) * use crowdin github actions to sync translations ([4416b0c](https://github.com/pocket-id/pocket-id/commit/4416b0c2489119f1eb37fda938951e9bf8ad61f0) by @stonith404) * combine CI checks into a single workflow file ([74e08f0](https://github.com/pocket-id/pocket-id/commit/74e08f0253cb619061d74dbeab2895e67d45d54e) by @stonith404) * add missing `cache-dependency-path` to go setup ([b0b09ce](https://github.com/pocket-id/pocket-id/commit/b0b09ce6cdbd3f4667389194272a6f7ee876d00b) by @stonith404) * add gofmt to stage hook ([54f28f8](https://github.com/pocket-id/pocket-id/commit/54f28f86d09dfbd8dc10702c893ac38a91f79a4f) by @stonith404) * update Fosite ([fd7951f](https://github.com/pocket-id/pocket-id/commit/fd7951f70efe0cb4dcaa182956b73e4ab26c543a) by @stonith404) * move shared files into `.github` repo ([3355b65](https://github.com/pocket-id/pocket-id/commit/3355b656b5e0eadbfa50089d741d0bd34a16ffb0) by @stonith404) * update golangci-lint ([#1833](https://github.com/pocket-id/pocket-id/pull/1833) by @ItalyPaleAle) * upgrade francis to 0.1.1 ([#1838](https://github.com/pocket-id/pocket-id/pull/1838) by @ItalyPaleAle) * upgrade Fosite ([a7f5d80](https://github.com/pocket-id/pocket-id/commit/a7f5d80aea7e6bf76c9e8e207857a315f4441a2f) by @stonith404) * fix flaky unit test ([5bf7e1d](https://github.com/pocket-id/pocket-id/commit/5bf7e1d2629788dd520a69a5d87d906293d2d58e) by @stonith404) * run CI checks on `v*` branches as well ([80a504b](https://github.com/pocket-id/pocket-id/commit/80a504b454f273efea6b692857f1ceb6a34b2e7f) by @stonith404) * remove unused issuer check from refresh token API validation ([03cab69](https://github.com/pocket-id/pocket-id/commit/03cab69d6bf50bbaf0d0255373b3c8362547bce0) by @stonith404) * upgrade Fosite ([6b6ef9a](https://github.com/pocket-id/pocket-id/commit/6b6ef9ad004faa8453470293215f9a0424743d84) by @stonith404) * Bump the “all-dependencies” group with 4 updates across multiple ecosystems ([#1851](https://github.com/pocket-id/pocket-id/pull/1851) by @dependabot\[bot]) * update AAGUIDs ([#1856](https://github.com/pocket-id/pocket-id/pull/1856) by @pocket-id-bot\[bot]) * restore the PR template in the repo so the PR quality check can read it ([09d4da8](https://github.com/pocket-id/pocket-id/commit/09d4da81a9553561dfeb7cec8a9f5808460fb127) by @stonith404) * Bump follow-redirects from 1.16.0 to 1.16.1 ([#1862](https://github.com/pocket-id/pocket-id/pull/1862) by @dependabot\[bot]) * bump Fosite ([b352c81](https://github.com/pocket-id/pocket-id/commit/b352c81c387b0df049ca7b448f4f5b70f2f79b3f) by @stonith404) **Full Changelog**: ## v2.18.0 - 2026-10-04 [Section titled “v2.18.0 - 2026-10-04”](#v2180---2026-10-04) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.18.0) ![Umpteenth](https://github.com/stonith404/umpteenth/raw/main/branding/lockup/lockup-on-dark.svg) If you are interested, checkout [Umpteenth](https://github.com/stonith404/umpteenth), a side project I just open-sourced. With Pocket ID for example we are using it to enrich the translation context in Crowdin automatically and very token efficiently. *** ### Features [Section titled “Features”](#features-1) * display passkey setup page for users coming from the login page ([4d2a5e4](https://github.com/pocket-id/pocket-id/commit/4d2a5e423e0038728344c4fef860b88591e1777b) by @stonith404) * add ability to search and select icons from selfh.st ([#1807](https://github.com/pocket-id/pocket-id/pull/1807) by @stonith404) * pin table row actions and add them to details pages ([3e201b5](https://github.com/pocket-id/pocket-id/commit/3e201b5bb254b8acaa7ae8bfafe6584723d685f5) by @stonith404) ### Other [Section titled “Other”](#other-2) * Bump the “all-dependencies” group with 4 updates across multiple ecosystems ([#1805](https://github.com/pocket-id/pocket-id/pull/1805) by @dependabot\[bot]) * add project_id to crowdin.yml ([5560060](https://github.com/pocket-id/pocket-id/commit/556006074cc8e05a753c593669a31aa353a24793) by @stonith404) * upgrade to SvelteKit 3 ([10efd16](https://github.com/pocket-id/pocket-id/commit/10efd1647c9cc3e83b247d4879587d9d74d80b16) by @stonith404) * fix vulnerable dependency versions ([c968123](https://github.com/pocket-id/pocket-id/commit/c9681234dd95c1f3e91c83b9ed01f09b44910df1) by @stonith404) * add vite-plus as node toolchain ([#1806](https://github.com/pocket-id/pocket-id/pull/1806) by @kmendell) **Full Changelog**: ## v2.17.0 - 2026-10-01 [Section titled “v2.17.0 - 2026-10-01”](#v2170---2026-10-01) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.17.0) ## Discussion [Section titled “Discussion”](#discussion) We just opened a [discussion](https://github.com/pocket-id/pocket-id/discussions/1802) about the current state of UI and UX of Pocket ID. We would love to get your feedback on it ❤️ ## Changelog [Section titled “Changelog”](#changelog) ### Features [Section titled “Features”](#features-2) * add FRANCIS_HOST to connect to a standalone Francis runtime ([#1768](https://github.com/pocket-id/pocket-id/pull/1768) by @ItalyPaleAle) * add OIDC back-channel logout ([#1734](https://github.com/pocket-id/pocket-id/pull/1734) by @alecrubin) * restore old behavior of automatically creating client secret ([d259a15](https://github.com/pocket-id/pocket-id/commit/d259a151318bc4a126d3433386afab591f65f778) by @stonith404) * redesign OIDC client details page ([e588e3f](https://github.com/pocket-id/pocket-id/commit/e588e3fc5dcbdd666b15e4017bae40602148cd65) by @stonith404) * add support Cloudflare location headers ([1a91eaa](https://github.com/pocket-id/pocket-id/commit/1a91eaa98c9f6839770c54a93f5f5d0eafb1f290) by @stonith404) * update authorization animation slightly ([1f67bb7](https://github.com/pocket-id/pocket-id/commit/1f67bb749313d482ff902eabf8b997e1167c97c8) by @stonith404) * make page transitions smoother and faster ([9c926bd](https://github.com/pocket-id/pocket-id/commit/9c926bd66f96b7667f9c3f78fe8d036504bfa99a) by @stonith404) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-2) * typo in fallback error message in interaction error page ([#1776](https://github.com/pocket-id/pocket-id/pull/1776) by @samuelQUANSAH) * handle localStorage not enabled gracefully ([#1786](https://github.com/pocket-id/pocket-id/pull/1786) by @ItalyPaleAle) * add 1min grace period to refresh token invalidation ([b2d4fae](https://github.com/pocket-id/pocket-id/commit/b2d4faebf703756f0afdc26cf910b58f9c2557fe) by @stonith404) * use URI validation message for API resources ([0235984](https://github.com/pocket-id/pocket-id/commit/02359840f21b7c4ee0293fd2125b5bff1a117560) by @stonith404) ### Documentation [Section titled “Documentation”](#documentation-1) * add missing swaggertype ([77a597d](https://github.com/pocket-id/pocket-id/commit/77a597dc4c45da23f783785642f1ad5b56865841) by @stonith404) ### Other [Section titled “Other”](#other-3) * use Pocket ID as identity for automated commits ([5086ece](https://github.com/pocket-id/pocket-id/commit/5086ece8db13c89f8dba838aa16e7e83c00af8e1) by @stonith404) * update AAGUIDs ([#1771](https://github.com/pocket-id/pocket-id/pull/1771) by @pocket-id-bot\[bot]) * pin all GH Actions to a specific SHA ([#1772](https://github.com/pocket-id/pocket-id/pull/1772) by @ItalyPaleAle) * Bump the “all-dependencies” group with 1 update across multiple ecosystems ([#1780](https://github.com/pocket-id/pocket-id/pull/1780) by @dependabot\[bot]) * update AAGUIDs ([#1788](https://github.com/pocket-id/pocket-id/pull/1788) by @pocket-id-bot\[bot]) * upgrade Francis to 0.1.0 ([#1787](https://github.com/pocket-id/pocket-id/pull/1787) by @ItalyPaleAle) * add Vercel OSS Program badge ([fd478ff](https://github.com/pocket-id/pocket-id/commit/fd478ffa81d41e79ead46dfb8a23a4780f52f5c7) by @kmendell) * bring `database.json` up-to-date ([642ccc8](https://github.com/pocket-id/pocket-id/commit/642ccc80d399af1100bbcf334f29f893a3270f87) by @stonith404) **Full Changelog**: ## v2.16.0 - 2026-09-20 [Section titled “v2.16.0 - 2026-09-20”](#v2160---2026-09-20) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.16.0) ### Features [Section titled “Features”](#features-3) * update the design of the email templates ([3249b0d](https://github.com/pocket-id/pocket-id/commit/3249b0dc8c00220b74e1008f94812cc02f6313c1) by @stonith404) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-3) * loading indicator not visible ([4ba2899](https://github.com/pocket-id/pocket-id/commit/4ba28992ff496caa20b6abe6f614eeb1fa777469) by @stonith404) * login with Yubikey not working in some Safari browsers ([4858db3](https://github.com/pocket-id/pocket-id/commit/4858db3bb4cf6619cad8682da61f0e793f24874c) by @stonith404) ### Other [Section titled “Other”](#other-4) * upgrade git cliff version ([98f9e39](https://github.com/pocket-id/pocket-id/commit/98f9e39785ae913d65ab3ad3523feaf907d3686e) by @stonith404) * update francis to rc7 ([#1769](https://github.com/pocket-id/pocket-id/pull/1769) by @ItalyPaleAle) * include frontend dependencies in SBOM ([5a1c6f0](https://github.com/pocket-id/pocket-id/commit/5a1c6f0547f779175107d31ea13d4f24000a1a65) by @stonith404) * include SBOMs for binaries ([8fe53ed](https://github.com/pocket-id/pocket-id/commit/8fe53ed42c522717c8c69612cc700e195b8ab2ea) by @stonith404) * replace local release script with action ([ba246e6](https://github.com/pocket-id/pocket-id/commit/ba246e61465378bc11571fcc77ca01c936fda174) by @stonith404) **Full Changelog**: ## v2.15.0 - 2026-09-19 [Section titled “v2.15.0 - 2026-09-19”](#v2150---2026-09-19) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.15.0) ### Features [Section titled “Features”](#features-4) * show admin UI warning for SQLite on networked filesystem ([#1713](https://github.com/pocket-id/pocket-id/pull/1713) by @ItalyPaleAle) * list allowed groups when hovering over allowed group count ([#1671](https://github.com/pocket-id/pocket-id/pull/1671) by @kmendell) * add explicit public keys for federated client credentials ([#1702](https://github.com/pocket-id/pocket-id/pull/1702) by @ItalyPaleAle) * use HS256 for Pocket ID’s own session tokens + fixes ([#1733](https://github.com/pocket-id/pocket-id/pull/1733) by @ItalyPaleAle) * replace individual save buttons with single “unsaved changes bar” ([#1757](https://github.com/pocket-id/pocket-id/pull/1757) by @stonith404) * include passkey icons based on AAGUID ([#1756](https://github.com/pocket-id/pocket-id/pull/1756) by @michaelbeaumont) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-4) * Update de.json Translation ([#1705](https://github.com/pocket-id/pocket-id/pull/1705) by @tw-) * show long login code button regardless where the user is coming from ([059d45d](https://github.com/pocket-id/pocket-id/commit/059d45d50ed9e6b1229295ab9ccb9d566d3910fe) by @stonith404) * make sorting of strings case insensitive ([3657012](https://github.com/pocket-id/pocket-id/commit/3657012f93e442327bdf11a36bd31acc26410803) by @stonith404) * trim values loaded from \_FILE env vars in AppConfig ([#1741](https://github.com/pocket-id/pocket-id/pull/1741) by @ItalyPaleAle) * serve bundled logo if no custom logo is set ([#1748](https://github.com/pocket-id/pocket-id/pull/1748) by @ItalyPaleAle) * add missing `await` to catch redirect invalid URL errors ([fd99a6b](https://github.com/pocket-id/pocket-id/commit/fd99a6b74207d1291bfd975c33d632d2f5ed9fd0) by @stonith404) * limit JPG and PNG pixels to prevent decompression bomb ([5cbacd8](https://github.com/pocket-id/pocket-id/commit/5cbacd81e67f8bb7340f01d0416524f4d48adb78) by @stonith404) * show more user friendly error page for authorize interaction failures ([81cb290](https://github.com/pocket-id/pocket-id/commit/81cb290bed57b7fc84b9102262ff3192ce9fae3e) by @stonith404) * don’t auto submit OAuth device codes ([43c0b79](https://github.com/pocket-id/pocket-id/commit/43c0b797fd7f3914b759a173a4518bed399e8de7) by @stonith404) * prevent PAR requirement bypass via conflicting request parameters ([2084dff](https://github.com/pocket-id/pocket-id/commit/2084dffd8d4a569d86f058376a1caa72a8755571) by @stonith404) * German translations for client secrets ([#1759](https://github.com/pocket-id/pocket-id/pull/1759) by @darioackermann) * preserve AAGUID icon hashes on Windows ([b816360](https://github.com/pocket-id/pocket-id/commit/b8163605acbdcf08772dc77582fcb48be1158906) by @stonith404) * default profile picture empty if username contains only one char ([4edfaf6](https://github.com/pocket-id/pocket-id/commit/4edfaf622a8f7c05b19f3fb4cc07cbe6984c7df9) by @stonith404) ### Documentation [Section titled “Documentation”](#documentation-2) * update AI Usage Policy ([d9e9df9](https://github.com/pocket-id/pocket-id/commit/d9e9df9960714f588ec65201afdde1cef26b0b9a) by @stonith404) * update PR template ([cad8b68](https://github.com/pocket-id/pocket-id/commit/cad8b68abc3eecd56a22a84aa897fe54c8deae66) by @stonith404) ### Other [Section titled “Other”](#other-5) * Bump the “all-dependencies” group with 2 updates across multiple ecosystems ([#1711](https://github.com/pocket-id/pocket-id/pull/1711) by @dependabot\[bot]) * add Hungarian language files ([dd2fc67](https://github.com/pocket-id/pocket-id/commit/dd2fc67c87c098632e7b915b6079b202df5d6f55) by @stonith404) * Bump the “all-dependencies” group with 3 updates across multiple ecosystems ([#1725](https://github.com/pocket-id/pocket-id/pull/1725) by @dependabot\[bot]) * update Go to `v1.27.0` ([f235104](https://github.com/pocket-id/pocket-id/commit/f235104aed02ea5aa2ff3e05c03fc151b34e0191) by @stonith404) * update golangci-lint version ([6ff9a5b](https://github.com/pocket-id/pocket-id/commit/6ff9a5ba7eb995a8db166ebfb119799325085a8e) by @stonith404) * update Francis to rc.2 ([#1728](https://github.com/pocket-id/pocket-id/pull/1728) by @ItalyPaleAle) * upgrade jwx to v4 ([#1730](https://github.com/pocket-id/pocket-id/pull/1730) by @ItalyPaleAle) * Bump google.golang.org/grpc from 1.83.0 to 1.83.1 in /backend ([#1736](https://github.com/pocket-id/pocket-id/pull/1736) by @dependabot\[bot]) * update Francis to rc.5 ([#1738](https://github.com/pocket-id/pocket-id/pull/1738) by @ItalyPaleAle) * Bump the “all-dependencies” group with 3 updates across multiple ecosystems ([#1739](https://github.com/pocket-id/pocket-id/pull/1739) by @dependabot\[bot]) * update Francis to rc.6 ([#1745](https://github.com/pocket-id/pocket-id/pull/1745) by @ItalyPaleAle) * Bump adm-zip from 0.6.0 to 0.6.1 ([#1747](https://github.com/pocket-id/pocket-id/pull/1747) by @dependabot\[bot]) * update AAGUIDs ([#1751](https://github.com/pocket-id/pocket-id/pull/1751) by @github-actions\[bot]) * Bump the “all-dependencies” group with 2 updates across multiple ecosystems ([#1742](https://github.com/pocket-id/pocket-id/pull/1742) by @dependabot\[bot]) * update vulnerable packages ([1ee34fd](https://github.com/pocket-id/pocket-id/commit/1ee34fddea9bfe1f08709387ec3186a792707c29) by @stonith404) * upgrade alpine packages on image build ([d2c2cda](https://github.com/pocket-id/pocket-id/commit/d2c2cdaa5d7f87541dcee69d7f6c57ad22a8bf09) by @stonith404) * Bump the “all-dependencies” group with 2 updates across multiple ecosystems ([#1760](https://github.com/pocket-id/pocket-id/pull/1760) by @dependabot\[bot]) * fix type checks ([c22003f](https://github.com/pocket-id/pocket-id/commit/c22003f6deff96482192d055a5e1c96e5991fcad) by @stonith404) * Bump go.opentelemetry.io/otel/exporters/zipkin from 1.44.0 to 1.45.0 in /backend ([#1765](https://github.com/pocket-id/pocket-id/pull/1765) by @dependabot\[bot]) * update backend dependencies ([6060c6e](https://github.com/pocket-id/pocket-id/commit/6060c6e12e62bfe2474f78caace77a205f73d498) by @stonith404) **Full Changelog**: ## v2.14.0 - 2026-08-18 [Section titled “v2.14.0 - 2026-08-18”](#v2140---2026-08-18) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.14.0) Tip Check out our first [YouTube video](https://youtu.be/JjoXz2u5r3Y) about how to protect your MCP servers with Pocket ID. ### Features [Section titled “Features”](#features-5) * add animated logo as default logo ([0c9a03e](https://github.com/pocket-id/pocket-id/commit/0c9a03e5193b52ff752134f7df39a24fae19dae2) by @stonith404) * hide apps without launch url on My Apps page ([3ca9a55](https://github.com/pocket-id/pocket-id/commit/3ca9a55c7135d785bc6089fa33dc6d8287fd3f59) by @stonith404) * support multiple client secrets per OIDC client ([#1679](https://github.com/pocket-id/pocket-id/pull/1679) by @ItalyPaleAle) * serve RFC 8414 authorization server metadata ([#1685](https://github.com/pocket-id/pocket-id/pull/1685) by @jfroy) * allow admins to auto grant APIs to CIMD clients ([#1692](https://github.com/pocket-id/pocket-id/pull/1692) by @stonith404) * improve tooltip design ([6a441b1](https://github.com/pocket-id/pocket-id/commit/6a441b1f9b139b41f33e70e06f4eb2ae7303cb28) by @stonith404) * reduce one time access code length for better UX ([a487c78](https://github.com/pocket-id/pocket-id/commit/a487c7855056b126b7b109f30ba7452c4539b04e) by @stonith404) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-5) * improve validation of app config variables ([9e637d5](https://github.com/pocket-id/pocket-id/commit/9e637d5aec178adb757cfdc961236f92731c16f3) by @stonith404) * wrong loading indicator shown on device page ([2f43ce4](https://github.com/pocket-id/pocket-id/commit/2f43ce41fe2d19365585453aa1d6d1528c73bee6) by @stonith404) * ignore unsupported grant types in client ID metadata documents ([#1682](https://github.com/pocket-id/pocket-id/pull/1682) by @ItalyPaleAle) * don’t show “show hidden apps” if none available ([03498e2](https://github.com/pocket-id/pocket-id/commit/03498e2f511eb91e1fea442be781b252828520c7) by @stonith404) * ignore trailing slash in resources ([9421d43](https://github.com/pocket-id/pocket-id/commit/9421d43f8ecab0f3d245d79196cb2f33818c8054) by @stonith404) * update de.json Translation ([#1699](https://github.com/pocket-id/pocket-id/pull/1699) by @tw-) * remove unnecessary information from oidc client details ([900346a](https://github.com/pocket-id/pocket-id/commit/900346a1c38b1d7b6d9897b7aa3cb9182f7dafed) by @stonith404) ### Documentation [Section titled “Documentation”](#documentation-3) * change logo image in README.md ([76f6b24](https://github.com/pocket-id/pocket-id/commit/76f6b249f26fb8d8b3215f519c6d39a311415606) by @stonith404) * add error responses to openapi spec ([#1684](https://github.com/pocket-id/pocket-id/pull/1684) by @aclerici38) ### Other [Section titled “Other”](#other-6) * Bump the “all-dependencies” group with 3 updates across multiple ecosystems ([#1668](https://github.com/pocket-id/pocket-id/pull/1668) by @dependabot\[bot]) * update francis to beta 21 ([#1669](https://github.com/pocket-id/pocket-id/pull/1669) by @ItalyPaleAle) * migrate LDAP sync to an actor ([#1651](https://github.com/pocket-id/pocket-id/pull/1651) by @ItalyPaleAle) * bump pnpm to v11.20.0 ([#1670](https://github.com/pocket-id/pocket-id/pull/1670) by @kmendell) * remove unnecessary curl dependency from Dockerfile ([987d1a8](https://github.com/pocket-id/pocket-id/commit/987d1a8b599eadaad32a4c68c9bcf25f12eeab2f) by @stonith404) * update Francis to beta 22 ([#1676](https://github.com/pocket-id/pocket-id/pull/1676) by @ItalyPaleAle) * update AAGUIDs ([#1678](https://github.com/pocket-id/pocket-id/pull/1678) by @github-actions\[bot]) * move `iss` param handling to Fosite ([1bb21c5](https://github.com/pocket-id/pocket-id/commit/1bb21c5d73d6942a9c6959f8be4e7fbe93e2eb29) by @stonith404) * fix flaky update application image e2e test ([#1690](https://github.com/pocket-id/pocket-id/pull/1690) by @ItalyPaleAle) * move API key cleanup job to actor ([#1687](https://github.com/pocket-id/pocket-id/pull/1687) by @ItalyPaleAle) * Bump the “all-dependencies” group with 4 updates across multiple ecosystems ([#1693](https://github.com/pocket-id/pocket-id/pull/1693) by @dependabot\[bot]) * use fix version for `github.com/italypaleale/go-kit` ([07580d9](https://github.com/pocket-id/pocket-id/commit/07580d9f9fc2ac457da7a7ba3d325068afffc6f2) by @stonith404) * update AAGUIDs ([#1696](https://github.com/pocket-id/pocket-id/pull/1696) by @github-actions\[bot]) * move remaining database cleanup jobs to actors ([#1698](https://github.com/pocket-id/pocket-id/pull/1698) by @ItalyPaleAle) * migrate SCIM sync to actor + add tests ([#1680](https://github.com/pocket-id/pocket-id/pull/1680) by @ItalyPaleAle) **Full Changelog**: ## v2.13.0 - 2026-08-07 [Section titled “v2.13.0 - 2026-08-07”](#v2130---2026-08-07) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.13.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-6) * retry qr code login polling for known transient gateway responses ([7039692](https://github.com/pocket-id/pocket-id/commit/703969278be2a6b2cae30ca89dba4b73b0c969fa) by @stonith404) * decrease QR code login session duration to 5 minutes ([e35be30](https://github.com/pocket-id/pocket-id/commit/e35be309a3d40064617ef0ad557476c93ba983a9) by @stonith404) * show more user-friendly error message if QR code has expired ([27199f6](https://github.com/pocket-id/pocket-id/commit/27199f61d4adaeca463db68980dae6c2a885c5b4) by @stonith404) * one-time-access-token CLI fails with “RuntimePSKs is required” ([#1637](https://github.com/pocket-id/pocket-id/pull/1637) by @salcatroppa) * session revoke fails if orphaned session tokens exist ([598895e](https://github.com/pocket-id/pocket-id/commit/598895e7c53df28598d578896f6396241e9e9ef7) by @stonith404) * disable api key auth for webauthn register endpoints ([db64b15](https://github.com/pocket-id/pocket-id/commit/db64b150be9046ee971f520b4c30f3b3d434facf) by @stonith404) * explicitly set SameSite to Lax for cookies ([69d55ad](https://github.com/pocket-id/pocket-id/commit/69d55ada6c695c47f764285ca9e94736e50a8103) by @stonith404) * explicitly require JSON for request bodies ([1238bf0](https://github.com/pocket-id/pocket-id/commit/1238bf0f378340d101c90295990b514131b10fe7) by @stonith404) * don’t rely on content length header for optional json binding ([2c7d1b6](https://github.com/pocket-id/pocket-id/commit/2c7d1b63e1a366718d0c1951475e791922bb2445) by @stonith404) * respect log level in HTTP request logs ([488c50e](https://github.com/pocket-id/pocket-id/commit/488c50ef95e3e88f3a0085a67b399819a4647c7f) by @stonith404) * don’t skip rate limits for loopback addresses ([140b5d3](https://github.com/pocket-id/pocket-id/commit/140b5d3cb440ccc7a30a3a1c9aae2f7a9d5efb4a) by @stonith404) * make OIDC client token lifetimes optional ([#1650](https://github.com/pocket-id/pocket-id/pull/1650) by @ItalyPaleAle) * in non-HA mode, increase AlarmLeaseDuration ([#1660](https://github.com/pocket-id/pocket-id/pull/1660) by @ItalyPaleAle) * separate TLS inputs and preserve certificate reloads ([#1653](https://github.com/pocket-id/pocket-id/pull/1653) by @stonith404) * brotli compression ignored ([#1661](https://github.com/pocket-id/pocket-id/pull/1661) by @stonith404) * align last signed in text left ([c87012a](https://github.com/pocket-id/pocket-id/commit/c87012ae01cb9e85ab305fffc40347297eff6ffb) by @stonith404) ### Features [Section titled “Features”](#features-6) * make oauth access tokens RFC 9068 compliant ([7c55bdf](https://github.com/pocket-id/pocket-id/commit/7c55bdf115fc5b7fea89ef5cd3c79dc926ddf5ac) by @stonith404) * implement OAuth Client ID Metadata Document ([#1526](https://github.com/pocket-id/pocket-id/pull/1526) by @jfroy) * add ability to customize session duration of clients ([#1641](https://github.com/pocket-id/pocket-id/pull/1641) by @stonith404) * add observability to actors ([#1646](https://github.com/pocket-id/pocket-id/pull/1646) by @ItalyPaleAle) * include Francis data in Pocket ID backups ([#1645](https://github.com/pocket-id/pocket-id/pull/1645) by @ItalyPaleAle) * add settings for limiting what passkeys can be used ([#1662](https://github.com/pocket-id/pocket-id/pull/1662) by @stonith404) ### Other [Section titled “Other”](#other-7) * preserve tab indentation for package.json in release script ([a1ebf4e](https://github.com/pocket-id/pocket-id/commit/a1ebf4e98b65fa465f99bfa2fb9694a903076a32) by @stonith404) * Bump the “all-dependencies” group with 3 updates across multiple ecosystems ([#1639](https://github.com/pocket-id/pocket-id/pull/1639) by @dependabot\[bot]) * use paraglide markup instead of custom implementation ([b08ac7b](https://github.com/pocket-id/pocket-id/commit/b08ac7bf7de04872a83913db19fc6392ecf7bd96) by @stonith404) * fix wrong database version in `database.json` ([281bea5](https://github.com/pocket-id/pocket-id/commit/281bea54d351128e29bb2e54455a7cb2e619554a) by @stonith404) * standardize API error handling ([#1635](https://github.com/pocket-id/pocket-id/pull/1635) by @stonith404) * add deepsec to gitignore ([e3e0ddc](https://github.com/pocket-id/pocket-id/commit/e3e0ddc192d01de35b8f907144ac66b6b2963ac0) by @stonith404) * upgrade vulnerable dependencies ([9320144](https://github.com/pocket-id/pocket-id/commit/9320144991fa0f9f6c1419af0c78c7e2395dc61e) by @stonith404) * remove unused curl dependency from Dockerfile ([98160b2](https://github.com/pocket-id/pocket-id/commit/98160b20a15056535bf12d357b7d97c63a165cd0) by @stonith404) * remove invalid unit test ([95809dd](https://github.com/pocket-id/pocket-id/commit/95809dd29cea92e30f54c34876305f7a27a595bd) by @stonith404) * use smaller francis.bin ([4fe6f06](https://github.com/pocket-id/pocket-id/commit/4fe6f0688c2760abfe35558ffc9126f3a1e9edc0) by @stonith404) * move GeoLite to its own package ([#1647](https://github.com/pocket-id/pocket-id/pull/1647) by @ItalyPaleAle) * fix formatting ([#1666](https://github.com/pocket-id/pocket-id/pull/1666) by @Copilot) **Full Changelog**: ## v2.12.0 - 2026-07-29 [Section titled “v2.12.0 - 2026-07-29”](#v2120---2026-07-29) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.12.0) Caution This version includes some security fixes, it’s highly recommended to update. ### Features [Section titled “Features”](#features-7) * add support for proxy protocol ([807bd9e](https://github.com/pocket-id/pocket-id/commit/807bd9e037f201ba1d87c65387091a61c5e65e54) by @stonith404) * add declarative user id configuration ([#1622](https://github.com/pocket-id/pocket-id/pull/1622) by @schnz) * migrate one-time and signup tokens to an actor ([#1611](https://github.com/pocket-id/pocket-id/pull/1611) by @ItalyPaleAle) * add support for declarative client secret configuration ([#1619](https://github.com/pocket-id/pocket-id/pull/1619) by @schnz) * add qr code alternative sign in method ([#1594](https://github.com/pocket-id/pocket-id/pull/1594) by @stonith404) * migrate app locks to Francis ([#1624](https://github.com/pocket-id/pocket-id/pull/1624) by @ItalyPaleAle) * drop user initiated one time access token login method ([0c27f73](https://github.com/pocket-id/pocket-id/commit/0c27f733b95de63855264327443cc65cf2ccefba) by @stonith404) * display country and city on qr code login approval screen ([9e72bc1](https://github.com/pocket-id/pocket-id/commit/9e72bc1c70506146919a21058f5e20b0f042082a) by @stonith404) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-7) * sync group membership for users added at creation time ([#1600](https://github.com/pocket-id/pocket-id/pull/1600) by @ItalyPaleAle) * relax Francis DB usage while HA is still WIP ([#1602](https://github.com/pocket-id/pocket-id/pull/1602) by @ItalyPaleAle) * honor webauthn user verification setting ([0983e91](https://github.com/pocket-id/pocket-id/commit/0983e911693396d8c807331ed867be5369f501f2) by @stonith404) * horizontal shadow of cards in light mode cut off ([599f7d1](https://github.com/pocket-id/pocket-id/commit/599f7d118df0225abf96429c42c26d7c627942a3) by @stonith404) * datatype mismatch between postgres and sqlite causes import to fail ([ad06ea6](https://github.com/pocket-id/pocket-id/commit/ad06ea6e008ea61edd5a84df0fbab3125ff047c7) by @stonith404) * show only accessible clients on “My Apps” page ([e10f66c](https://github.com/pocket-id/pocket-id/commit/e10f66c07a8f4a8d42a03bb7edda14d4bf9ba31d) by @stonith404) * autofocus one time input fields ([#1605](https://github.com/pocket-id/pocket-id/pull/1605) by @James18232) * enforce user verification for login assertions ([4743d59](https://github.com/pocket-id/pocket-id/commit/4743d5967a6b7e53d6d8c670c62f0bdea3abd4af) by @stonith404) * make oidc device code redemption atomic ([6bd058a](https://github.com/pocket-id/pocket-id/commit/6bd058ac46c771ff7dc133b72f42c6c341dba6f4) by @stonith404) * race condition in initial admin setup ([ca28ddc](https://github.com/pocket-id/pocket-id/commit/ca28ddcb04ce2905aaad0c5255caceae723cda56) by @stonith404) * fail early if webauthn session invalid ([968f97f](https://github.com/pocket-id/pocket-id/commit/968f97fa6174a1319bd33309bf647be3d11bd816) by @stonith404) ### Other [Section titled “Other”](#other-8) * Bump the “all-dependencies” group with 3 updates across multiple ecosystems ([#1599](https://github.com/pocket-id/pocket-id/pull/1599) by @dependabot\[bot]) * update AAGUIDs ([#1608](https://github.com/pocket-id/pocket-id/pull/1608) by @github-actions\[bot]) * use actors for db configuration ([#1604](https://github.com/pocket-id/pocket-id/pull/1604) by @ItalyPaleAle) * remove not used permissions ([942bb3b](https://github.com/pocket-id/pocket-id/commit/942bb3be2e92bd7b6bf1d89c40cab49544194d43) by @stonith404) * upgrade vulnerable dependencies ([f6b02ef](https://github.com/pocket-id/pocket-id/commit/f6b02efe4542cd3a57ba222c42fafe1e968a32d8) by @stonith404) * fix missing data in `database.json` ([6e859de](https://github.com/pocket-id/pocket-id/commit/6e859de2dd55dfc59d9cde3fab5d7a9789c6aca9) by @stonith404) * Bump the “all-dependencies” group with 3 updates across multiple ecosystems ([#1621](https://github.com/pocket-id/pocket-id/pull/1621) by @dependabot\[bot]) * use `NewTextHandler` instead of `NewHandler` for tint ([8563934](https://github.com/pocket-id/pocket-id/commit/8563934fd5d410c13e9ff58e56a07bef0ea22726) by @stonith404) * run unit tests on windows and linux ([31d62c6](https://github.com/pocket-id/pocket-id/commit/31d62c65e59f184d13aeef74860839665c183c78) by @stonith404) * correctly close filesystems ([6bd4679](https://github.com/pocket-id/pocket-id/commit/6bd4679bab03e16b85a0591d2c95ebdd530cf785) by @stonith404) * modularize email module and use actor for email verification ([#1625](https://github.com/pocket-id/pocket-id/pull/1625) by @stonith404) * pin version of fosite fork ([91d3712](https://github.com/pocket-id/pocket-id/commit/91d37126fa916932a1097a4a60c161965aa24e50) by @stonith404) * translations remove unused translation strings ([d5eb3fe](https://github.com/pocket-id/pocket-id/commit/d5eb3fe62c5ddbfd7f2bc5c116f755dccd40d6b4) by @stonith404) * enforce eslint rules ([9060291](https://github.com/pocket-id/pocket-id/commit/9060291475aaadb5be2149213cfb647bb8381247) by @stonith404) * upgrade vulnerable dependencies ([0c5e014](https://github.com/pocket-id/pocket-id/commit/0c5e0149cd070b39e5da7722471885432d5b5452) by @stonith404) **Full Changelog**: ## v2.11.0 - 2026-07-13 [Section titled “v2.11.0 - 2026-07-13”](#v2110---2026-07-13) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.11.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-8) * postgres migration 20250822 remove public schema references ([#1582](https://github.com/pocket-id/pocket-id/pull/1582) by @MarcoScabbiolo) * allow insecure callback URLs by default until next major release ([d9ead47](https://github.com/pocket-id/pocket-id/commit/d9ead47d19451b256336b7d0eb46606a236928f3) by @stonith404) * sort signup tokens by creation date explicitly ([77398a5](https://github.com/pocket-id/pocket-id/commit/77398a558df45e1e332316afbb0f0c5e416350ea) by @stonith404) * login code mobile ux ([#1584](https://github.com/pocket-id/pocket-id/pull/1584) by @James18232) * `INTERNAL_APP_URL` not reflected in UI URLs ([316cf47](https://github.com/pocket-id/pocket-id/commit/316cf47cebdb7337cef13a533a8105ef4364b6f5) by @stonith404) * ignore tab URL hashes in navigation history ([a3f27ec](https://github.com/pocket-id/pocket-id/commit/a3f27ec2ec1ce784ca11e5fb41f92a0367715393) by @stonith404) * block link-local addresses in SSRF protection ([9714296](https://github.com/pocket-id/pocket-id/commit/9714296efb3768e4f29479f48628318565a3bed7) by @stonith404) ### Features [Section titled “Features”](#features-8) * add support for CIDR and IP address lists in `TRUST_PROXY` ([187cd8d](https://github.com/pocket-id/pocket-id/commit/187cd8ddcd4d6babec73bdf7e81eab2dee1ade04) by @stonith404) ### Other [Section titled “Other”](#other-9) * manage instance ID in the KV table ([#1579](https://github.com/pocket-id/pocket-id/pull/1579) by @ItalyPaleAle) * Bump the “all-dependencies” group with 3 updates across multiple ecosystems ([#1578](https://github.com/pocket-id/pocket-id/pull/1578) by @dependabot\[bot]) * remove low demand issue closer ([bb03660](https://github.com/pocket-id/pocket-id/commit/bb03660bd7d48dfd0b022936dabd2b2880c9b382) by @stonith404) **Full Changelog**: ## v2.10.0 - 2026-07-10 [Section titled “v2.10.0 - 2026-07-10”](#v2100---2026-07-10) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.10.0) ### Features [Section titled “Features”](#features-9) * upgrade shadcn components ([80509c8](https://github.com/pocket-id/pocket-id/commit/80509c83ee0ce92b416286217c11f116d5b9fe2a) by @stonith404) * add ability to skip consent for client ([d467855](https://github.com/pocket-id/pocket-id/commit/d4678558708542719c5d3cc48c48d3053f37800c) by @stonith404) * prompt admin with PKCE client support hint ([#1499](https://github.com/pocket-id/pocket-id/pull/1499) by @James18232) * login code input boxes ([#1545](https://github.com/pocket-id/pocket-id/pull/1545) by @James18232) * drop TOFU support for callback URL ([931a6c2](https://github.com/pocket-id/pocket-id/commit/931a6c2adb39fb8cdfe18487f4206f8848b3d026) by @stonith404) * add OAuth APIs with scoped permissions ([#1542](https://github.com/pocket-id/pocket-id/pull/1542) by @stonith404) * add support for unencrypted OIDC request parameter ([25dcad7](https://github.com/pocket-id/pocket-id/commit/25dcad757a7d7670bfd8d4d4ac209e26dc919596) by @stonith404) * add description field to oidc clients ([#1547](https://github.com/pocket-id/pocket-id/pull/1547) by @seanmckenzie428) * add tab bar navigation for crowded pages ([28a553f](https://github.com/pocket-id/pocket-id/commit/28a553f63b85ecccaa764279af5f65ea1bf2d013) by @stonith404) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-9) * login code null submission and login code length check ([#1512](https://github.com/pocket-id/pocket-id/pull/1512) by @James18232) * various bugs in observability / OTel ([#1564](https://github.com/pocket-id/pocket-id/pull/1564) by @ItalyPaleAle) * /authorize endpoint crashes when list of scopes is empty ([#1575](https://github.com/pocket-id/pocket-id/pull/1575) by @ItalyPaleAle) * mobile layout improvements ([2910c51](https://github.com/pocket-id/pocket-id/commit/2910c517bb7545f932c34321907299064b08bb10) by @stonith404) ### Documentation [Section titled “Documentation”](#documentation-4) * add link to API docs ([968d072](https://github.com/pocket-id/pocket-id/commit/968d07229eeefa763fe981e5c7e4970d5640c783) by @stonith404) * fix wrong OpenAPI documentation ([da3677f](https://github.com/pocket-id/pocket-id/commit/da3677f33d50c96f06ee1d8f65d9f802f67af270) by @stonith404) ### Other [Section titled “Other”](#other-10) * close low-demand feature requests ([35987b9](https://github.com/pocket-id/pocket-id/commit/35987b9c8d44efb08928d031ab9f1e84eda9882f) by @stonith404) * Bump the “all-dependencies” group with 2 updates across multiple ecosystems ([#1528](https://github.com/pocket-id/pocket-id/pull/1528) by @dependabot\[bot]) * fix locators after shadcn upgrade ([dbbe2a4](https://github.com/pocket-id/pocket-id/commit/dbbe2a403aa6afc39e14cf559bd074c6640e3b0c) by @stonith404) * use fosite for OAuth 2.0 logic ([#1520](https://github.com/pocket-id/pocket-id/pull/1520) by @stonith404) * wrap last two migrations into transaction ([cf9a319](https://github.com/pocket-id/pocket-id/commit/cf9a31986f521451bc9e1c2754a09ee2d141cd57) by @stonith404) * remove dead code ([519cda0](https://github.com/pocket-id/pocket-id/commit/519cda0eef1083274deed9bf6c501b815986241a) by @stonith404) * update vulnerable dependencies ([e538ea0](https://github.com/pocket-id/pocket-id/commit/e538ea0bf1ba4d5f70f977c7021bfa4f4543070e) by @stonith404) * fix flaky test ([7eaaea7](https://github.com/pocket-id/pocket-id/commit/7eaaea717b418c167b733723eeb000073c6915fe) by @stonith404) * add AGENTS.md ([d0243fe](https://github.com/pocket-id/pocket-id/commit/d0243fe396fb4ae2ec8d66ab95c80c8a283a631b) by @stonith404) * use goreleaser for binaries and static image builds ([#1478](https://github.com/pocket-id/pocket-id/pull/1478) by @kmendell) * add support for Docker Hub ([99ab38d](https://github.com/pocket-id/pocket-id/commit/99ab38dc799d07d4d91863199b1350fb7d06e03e) by @stonith404) * remove static next image tag ([49305ed](https://github.com/pocket-id/pocket-id/commit/49305ed1f98d838167703d3dc2f6e3e5786fb9fc) by @stonith404) * don’t build unnecessary binaries for `next` image ([4b957a0](https://github.com/pocket-id/pocket-id/commit/4b957a0106899666b55420b61d2bb12d08d82022) by @stonith404) * change Depot project ([cdc2374](https://github.com/pocket-id/pocket-id/commit/cdc23744ae1cb731184828afe326fc2a1712c02f) by @stonith404) * don’t tag `next` image with current version ([cf54786](https://github.com/pocket-id/pocket-id/commit/cf54786cc3bfe59bd01e8d5cbb4a3ccabb7d6466) by @stonith404) * add exempt user to PR quality checks ([254ae88](https://github.com/pocket-id/pocket-id/commit/254ae88cda67ecc1095b0b738630388c93d90c44) by @stonith404) * migrate API key functionality to single `apikey` module ([9fce987](https://github.com/pocket-id/pocket-id/commit/9fce98710679e522233c3b7af8d3b6cd2ce5594c) by @stonith404) * migrate Webauthn functionality to single `webauthn` module ([58fcf7c](https://github.com/pocket-id/pocket-id/commit/58fcf7cbe665be8d7670170097735fe8efe31c6f) by @stonith404) * migrate signup functionality to single `usersignup` module ([ecad31c](https://github.com/pocket-id/pocket-id/commit/ecad31cae2dbbc51d15a7007601829c57accff75) by @stonith404) * make API key renewal date picker navigation date-independent ([#1560](https://github.com/pocket-id/pocket-id/pull/1560) by @ItalyPaleAle) * integrate Francis actor framework for background jobs, cron scheduling, and rate limiting ([#1556](https://github.com/pocket-id/pocket-id/pull/1556) by @ItalyPaleAle) * Bump the “all-dependencies” group with 3 updates across multiple ecosystems ([#1563](https://github.com/pocket-id/pocket-id/pull/1563) by @dependabot\[bot]) * use go-kit for sending emails ([#1565](https://github.com/pocket-id/pocket-id/pull/1565) by @ItalyPaleAle) * update AAGUIDs ([#1567](https://github.com/pocket-id/pocket-id/pull/1567) by @github-actions\[bot]) * move Pocket ID specific logic from Fosite into Pocket ID repo ([9a94aa0](https://github.com/pocket-id/pocket-id/commit/9a94aa0694abda5bdd7c9380cbadc1f080a8027e) by @stonith404) * update Fosite version ([337fc6f](https://github.com/pocket-id/pocket-id/commit/337fc6fd1ec53aa65275f5ad964869462664a194) by @stonith404) * pass transaction to `resolveResource` ([7667377](https://github.com/pocket-id/pocket-id/commit/7667377c98c01f45dc5e959c999c60143efca1ef) by @stonith404) * remove redundant dtos ([fa2d08c](https://github.com/pocket-id/pocket-id/commit/fa2d08cb6d60bc3c9d8865c36c07ef8868e8ed9e) by @stonith404) * rename migrations ([c72da58](https://github.com/pocket-id/pocket-id/commit/c72da58eaf45eafff3232bcc050fd87e84ae050f) by @stonith404) * remove duplicate fosite config properties ([190914f](https://github.com/pocket-id/pocket-id/commit/190914fd72481c2da7372215f369a5b96feed3f0) by @stonith404) * fix migration version in `database.json` ([a5f2192](https://github.com/pocket-id/pocket-id/commit/a5f2192d67045cca63a4e0038e118986754d4184) by @stonith404) * fix wrong migration name ([ce7d3a7](https://github.com/pocket-id/pocket-id/commit/ce7d3a7e1d6ab08696a149fa8805fcb99337afa9) by @stonith404) * run formatter ([59a6868](https://github.com/pocket-id/pocket-id/commit/59a6868ecdb017354d4dfd8d70c4ba0710f02f08) by @stonith404) * upgrade go version ([f62d476](https://github.com/pocket-id/pocket-id/commit/f62d476c56d39f7f20c443eb430462e9141d31fa) by @stonith404) **Full Changelog**: ## v2.9.0 - 2026-06-16 [Section titled “v2.9.0 - 2026-06-16”](#v290---2026-06-16) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.9.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-10) * issues with loading new font ([#1496](https://github.com/pocket-id/pocket-id/pull/1496) by @MelvinSnijders) * PAR parameters not respected by authorize page ([3d9d4de](https://github.com/pocket-id/pocket-id/commit/3d9d4de61940747c64f4a5a4ba24010be2a2fbb6) by @stonith404) * add responsive css for api/user/group/client page add buttons ([#1508](https://github.com/pocket-id/pocket-id/pull/1508) by @James18232) * load Gloock font from static path instead of inline ([89b4abb](https://github.com/pocket-id/pocket-id/commit/89b4abb8b5cc71b62f458f966f2778259b167838) by @stonith404) * update terminology from public key code exchange to proof key co… ([#1515](https://github.com/pocket-id/pocket-id/pull/1515) by @maxwassiljew) * callback URL validation not validated if prompt=none ([8a75774](https://github.com/pocket-id/pocket-id/commit/8a7577497131229badb35cb4b3a4227b1300afff) by @stonith404) * passkey card not rounded ([84678c3](https://github.com/pocket-id/pocket-id/commit/84678c3a7bfa1f601261943f03aa935626fe54a2) by @stonith404) ### Documentation [Section titled “Documentation”](#documentation-5) * add AI Usage Policy to CONTRIBUTING.md ([fea933b](https://github.com/pocket-id/pocket-id/commit/fea933b62d6a2899bf1e46fc75dab8b6bca81a0f) by @stonith404) * add PR template ([bf9f76b](https://github.com/pocket-id/pocket-id/commit/bf9f76bbd5b8d49dabda74f1c3de5120ea5db698) by @stonith404) * add “needs more upvotes” label as default ([fc42f62](https://github.com/pocket-id/pocket-id/commit/fc42f6211d410ea8db75018292df8f311078a7fe) by @stonith404) * fix link to watchtower repo ([#1500](https://github.com/pocket-id/pocket-id/pull/1500) by @wollew) ### Features [Section titled “Features”](#features-10) * add support for Pushed Authorization Requests (RFC9126) ([#1404](https://github.com/pocket-id/pocket-id/pull/1404) by @Zenithar) ### Other [Section titled “Other”](#other-11) * fix linter issues ([4f97cd4](https://github.com/pocket-id/pocket-id/commit/4f97cd4188b6028e955c8dc62e122ec409b32db3) by @stonith404) * update AAGUIDs ([#1511](https://github.com/pocket-id/pocket-id/pull/1511) by @github-actions\[bot]) * run svelte check and unit tests in breaking branches ([83b45f6](https://github.com/pocket-id/pocket-id/commit/83b45f682dc89b2019b1812157157f431dfd3ad7) by @stonith404) * run formatter ([2726ddd](https://github.com/pocket-id/pocket-id/commit/2726ddd0c23ab6ae22f307bf8d377fdfd73e1c14) by @stonith404) * bump vite from 8.0.13 to 8.0.16 ([#1521](https://github.com/pocket-id/pocket-id/pull/1521) by @dependabot\[bot]) * npm dependabot not run from root ([c0d96a0](https://github.com/pocket-id/pocket-id/commit/c0d96a0b1349d7dd0dec65c78dcdc2e043713ff8) by @stonith404) * fix wrong assertion ([effd2a1](https://github.com/pocket-id/pocket-id/commit/effd2a146f9b85d8bf1df203b4970aafc7ae24f8) by @stonith404) * Bump the “all-dependencies” group with 4 updates across multiple ecosystems ([#1523](https://github.com/pocket-id/pocket-id/pull/1523) by @dependabot\[bot]) **Full Changelog**: ## v2.8.0 - 2026-05-31 [Section titled “v2.8.0 - 2026-05-31”](#v280---2026-05-31) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.8.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-11) * delete refresh tokens on end-session to prevent reuse after logout ([#1458](https://github.com/pocket-id/pocket-id/pull/1458) by @wucm667) * return 404 status code for `.well-known` routes if not found ([714b5b3](https://github.com/pocket-id/pocket-id/commit/714b5b3307bb012b94e66e8dcb1de93a2d62eceb) by @stonith404) * add `email_verified` to reserved claims list ([8b22fca](https://github.com/pocket-id/pocket-id/commit/8b22fcaaa475984bb4c42306487035073d7c47e3) by @stonith404) * reject unknown PKCE code challenge methods ([ce6bdb9](https://github.com/pocket-id/pocket-id/commit/ce6bdb9d7e6c0f1eaaa21ddb6d808e41088a38b8) by @stonith404) * make stream of downloaded logos seekable for S3 checksum calculation ([cc9163f](https://github.com/pocket-id/pocket-id/commit/cc9163f577280d7c278dc744e20d0505dbe83ede) by @stonith404) * scope confirmation wasn’t shown if account selection was prompted ([272d147](https://github.com/pocket-id/pocket-id/commit/272d1479bd64b4a068bfe4dfa5ba4cd3c5e90505) by @stonith404) * add support for unix socket mode in healthcheck ([a712196](https://github.com/pocket-id/pocket-id/commit/a71219637af1746e9faba5274b6095da676ec555) by @stonith404) * restore cross-platform binary builds ([7027296](https://github.com/pocket-id/pocket-id/commit/7027296632ab82cd9930f2fbe60054c2421688c4) by @stonith404) ### Documentation [Section titled “Documentation”](#documentation-6) * update SECURITY.md ([bb5a111](https://github.com/pocket-id/pocket-id/commit/bb5a111e3d51ad56fc074df7083022e3d4e25369) by @stonith404) ### Features [Section titled “Features”](#features-11) * delete OAuth refresh token on RP initiated logout ([#1480](https://github.com/pocket-id/pocket-id/pull/1480) by @stonith404) * remove EXIF/XMP metadata from uploaded images ([#1477](https://github.com/pocket-id/pocket-id/pull/1477) by @stonith404) * add support for `response_mode=fragment` ([0c95b7c](https://github.com/pocket-id/pocket-id/commit/0c95b7c3cc171ed77b51f236009b5ff659da0bec) by @stonith404) * add support for systemd socket activation ([#1479](https://github.com/pocket-id/pocket-id/pull/1479) by @deviant) * improve design trough the whole application ([b3d40a4](https://github.com/pocket-id/pocket-id/commit/b3d40a476b35cfa2451749e9a3d307b7babaeb6b) by @stonith404) ### Other [Section titled “Other”](#other-12) * update AAGUIDs ([#1476](https://github.com/pocket-id/pocket-id/pull/1476) by @github-actions\[bot]) * upgrade dependencies ([91c2ea2](https://github.com/pocket-id/pocket-id/commit/91c2ea2a6616a500922365d1789f1fa1ba66c112) by @stonith404) * remove deprecated http2 package ([e56dc12](https://github.com/pocket-id/pocket-id/commit/e56dc124cee4d3c176c89e7d574ddfde089bcbd1) by @stonith404) * apply go 1.26.0 syntax updated ([8ad95b8](https://github.com/pocket-id/pocket-id/commit/8ad95b8af17ba8cbb62168ed0bb54c87e3df379c) by @stonith404) * delete refresh tokens on end-session to prevent reuse after logout ([b27a52a](https://github.com/pocket-id/pocket-id/commit/b27a52a5915228383dbdbf0a2c353452cd351d0f) by @stonith404) * use dependabot for automatic dependency upgrades ([b9fdd53](https://github.com/pocket-id/pocket-id/commit/b9fdd530c0f370f2fccb6251d700aa6f9bdf4124) by @stonith404) * fix invalid schema ([e8c398f](https://github.com/pocket-id/pocket-id/commit/e8c398ffbd6545f76c983f01556bb3b73d40a728) by @stonith404) * update AAGUIDs ([#1487](https://github.com/pocket-id/pocket-id/pull/1487) by @github-actions\[bot]) * use custom Playwright route for callback URL checks ([f134247](https://github.com/pocket-id/pocket-id/commit/f13424720b7f5da3978988f0f9169cf303971a13) by @stonith404) * fix linter issues ([bc4f75c](https://github.com/pocket-id/pocket-id/commit/bc4f75c44f12a71380042ad4c140d41f4dddc7dd) by @stonith404) * don’t compare hashes of profile pictures ([9ad2bfc](https://github.com/pocket-id/pocket-id/commit/9ad2bfc7b30e0eb2d7ae1406874b8caba5a1f121) by @stonith404) * run formatter ([0616aba](https://github.com/pocket-id/pocket-id/commit/0616abaf7f079d0a35543258e13aa5b4acb4adc0) by @stonith404) * use fixed minor version of Go ([e046a03](https://github.com/pocket-id/pocket-id/commit/e046a03364f00001f8699aaa7e902b33c2661118) by @stonith404) **Full Changelog**: ## v2.7.0 - 2026-05-11 [Section titled “v2.7.0 - 2026-05-11”](#v270---2026-05-11) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.7.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-12) * add `_FILE` support for `S3_SECRET_ACCESS_KEY_FILE` env var ([#1452](https://github.com/pocket-id/pocket-id/pull/1452) by @ItalyPaleAle) * invalidate cache when changing image ([#1462](https://github.com/pocket-id/pocket-id/pull/1462) by @GameTec-live) * fall back to Basic auth when PKCE puts client_id in body ([#1466](https://github.com/pocket-id/pocket-id/pull/1466) by @mgabor3141) ### Documentation [Section titled “Documentation”](#documentation-7) * add missing /api prefix to app config swagger routes ([#1454](https://github.com/pocket-id/pocket-id/pull/1454) by @aclerici38) ### Features [Section titled “Features”](#features-12) * add support for response_mode=form_post ([#1360](https://github.com/pocket-id/pocket-id/pull/1360) by @Johnwulp) * add support for “select_account” prompt ([#1453](https://github.com/pocket-id/pocket-id/pull/1453) by @ItalyPaleAle) ### Other [Section titled “Other”](#other-13) * add script to update deps ([f9f93f0](https://github.com/pocket-id/pocket-id/commit/f9f93f0ef164426d4d4cfb58fcf59ce30b686130) by @stonith404) * upgrade dependencies ([20df033](https://github.com/pocket-id/pocket-id/commit/20df033c1fc3d737927447206b4f5e65d3ab4a40) by @stonith404) * post dependency upgrade fixes ([e33a9b8](https://github.com/pocket-id/pocket-id/commit/e33a9b8c888988f7b2e6c500e72d53b57db01f34) by @stonith404) * migrate github actions runners to depot runners ([#1329](https://github.com/pocket-id/pocket-id/pull/1329) by @kmendell) * fix caching of ldap-cli e2e tests docker build ([#1457](https://github.com/pocket-id/pocket-id/pull/1457) by @kmendell) * fix incorrect container name variable ([5c7e5f6](https://github.com/pocket-id/pocket-id/commit/5c7e5f680bb70d3056b11f1a33669cc4bd9a1e17) by @kmendell) **Full Changelog**: ## v2.6.2 - 2026-04-21 [Section titled “v2.6.2 - 2026-04-21”](#v262---2026-04-21) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.6.2) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-13) * return correct byte count in HEAD request writer ([#1443](https://github.com/pocket-id/pocket-id/pull/1443) by @ahampal) * improve keyboard navigation and screen-reader labels ([#1445](https://github.com/pocket-id/pocket-id/pull/1445) by @bjoernch) ### Other [Section titled “Other”](#other-14) * upgrade to vite 8.0 and pnpm 10.33.0 ([#1446](https://github.com/pocket-id/pocket-id/pull/1446) by @kmendell) **Full Changelog**: ## v2.6.1 - 2026-04-21 [Section titled “v2.6.1 - 2026-04-21”](#v261---2026-04-21) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.6.1) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-14) * restore login screen background from not showing up ([975d3c7](https://github.com/pocket-id/pocket-id/commit/975d3c79c6a882291c69b31d25bfcd8b7896528c) by @kmendell) ### Other [Section titled “Other”](#other-15) * ignore webauthn type for swagger generation ([ce4b89d](https://github.com/pocket-id/pocket-id/commit/ce4b89da650f025747fd0dd45eab5cebe29f5a93) by @kmendell) * update golangci-lint ([#1440](https://github.com/pocket-id/pocket-id/pull/1440) by @ItalyPaleAle) * Add catalan language ([#1436](https://github.com/pocket-id/pocket-id/pull/1436) by @mcasellas) **Full Changelog**: ## v2.6.0 - 2026-04-19 [Section titled “v2.6.0 - 2026-04-19”](#v260---2026-04-19) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.6.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-15) * disable callback URLs with protocols “javascript” and “data” ([#1397](https://github.com/pocket-id/pocket-id/pull/1397) by @ItalyPaleAle) * strip Root prefix from S3 List() returned paths ([#1413](https://github.com/pocket-id/pocket-id/pull/1413) by @vtmocanu) * use valid Tailwind v4 transition class for auth animation squares ([#1415](https://github.com/pocket-id/pocket-id/pull/1415) by @CoolShades) * resolve posixGroup memberUid as bare usernames ([#1422](https://github.com/pocket-id/pocket-id/pull/1422) by @gucong3000) * prevent flickering if no background image is set on login page ([027e6f0](https://github.com/pocket-id/pocket-id/commit/027e6f078da0eec712ae22a04b37c86110cb262b) by @stonith404) * improve form input layout if description next to it is multi col ([9ec4683](https://github.com/pocket-id/pocket-id/commit/9ec4683d18036ba1945bffd4bce14ec4c2dff7f9) by @stonith404) * access token renewal bypasses important checks ([978ac87](https://github.com/pocket-id/pocket-id/commit/978ac87deffec58beaccd15aead975e91b94c8a5) by @stonith404) ### Features [Section titled “Features”](#features-13) * add ability to revoke passkeys of users as admin ([#1386](https://github.com/pocket-id/pocket-id/pull/1386) by @jose-d) * add auth method claim (`amr`) to tokens ([#1433](https://github.com/pocket-id/pocket-id/pull/1433) by @stonith404) * add TLS support for HTTP/2 server ([#1429](https://github.com/pocket-id/pocket-id/pull/1429) by @IngmarStein) * add OpenID Connect `prompt` Parameter Handling ([#1299](https://github.com/pocket-id/pocket-id/pull/1299) by @rjaakke) * return not found. on `/setup` if already completed ([444f7ff](https://github.com/pocket-id/pocket-id/commit/444f7ff2b0269c12f1dba334a37d7db2007e172f) by @stonith404) ### Other [Section titled “Other”](#other-16) * update AAGUIDs ([#1403](https://github.com/pocket-id/pocket-id/pull/1403) by @github-actions\[bot]) * upgrade dependencies ([f8f7222](https://github.com/pocket-id/pocket-id/commit/f8f7222468dad90f630ae18f7c3fd78e37ba3f77) by @stonith404) * combobox not closed in e2e test ([fbdb93f](https://github.com/pocket-id/pocket-id/commit/fbdb93f1a768a05e6e3f2c6fd32b5de50a745bc6) by @stonith404) * Security upgrade alpine from latest to 3.23.4 ([#1431](https://github.com/pocket-id/pocket-id/pull/1431) by @stonith404) * security upgrade alpine from latest to 3.23.4 ([#1432](https://github.com/pocket-id/pocket-id/pull/1432) by @stonith404) * add Catalan language files ([4f09de2](https://github.com/pocket-id/pocket-id/commit/4f09de2cfc7d1e92632116821493a670fc7ee80d) by @stonith404) * reduce complexity of `ValidateEnvConfig` and `initRouter` ([a0cb574](https://github.com/pocket-id/pocket-id/commit/a0cb57431372c2bcc59904342597845e92a42a93) by @stonith404) * pass context to `shutdownServer` ([ff26c42](https://github.com/pocket-id/pocket-id/commit/ff26c4273a061b7d2c84e7b74f1e0f9e0acc6eb0) by @stonith404) **Full Changelog**: ## v2.5.0 - 2026-03-26 [Section titled “v2.5.0 - 2026-03-26”](#v250---2026-03-26) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.5.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-16) * better error messages when there’s another instance of Pocket ID running ([#1370](https://github.com/pocket-id/pocket-id/pull/1370) by @ItalyPaleAle) * move tooltip inside of form input to prevent shifting ([#1369](https://github.com/pocket-id/pocket-id/pull/1369) by @GameTec-live) * derive LDAP admin access from group membership ([#1374](https://github.com/pocket-id/pocket-id/pull/1374) by @kmendell) * avoid fmt.Sprintf on custom GeoLiteDBUrl without %s placeholder ([#1384](https://github.com/pocket-id/pocket-id/pull/1384) by @choyri) * show a warning when SQLite DB is stored on NFS/SMB/FUSE ([#1381](https://github.com/pocket-id/pocket-id/pull/1381) by @ItalyPaleAle) * empty background restore after reboot ([#1379](https://github.com/pocket-id/pocket-id/pull/1379) by @taoso) * allow one-char username on signup ([#1378](https://github.com/pocket-id/pocket-id/pull/1378) by @taoso) * separate querying LDAP and updating DB during sync ([#1371](https://github.com/pocket-id/pocket-id/pull/1371) by @ItalyPaleAle) ### Features [Section titled “Features”](#features-14) * allow use of svg, png, and ico images types for favicon ([#1289](https://github.com/pocket-id/pocket-id/pull/1289) by @taoso) * allow clearing background image ([#1290](https://github.com/pocket-id/pocket-id/pull/1290) by @taoso) * add `token_endpoint_auth_methods_supported` to `.well-known` ([#1388](https://github.com/pocket-id/pocket-id/pull/1388) by @owenvoke) * add TRUSTED_PLATFORM environment variable for gin ([#1372](https://github.com/pocket-id/pocket-id/pull/1372) by @choyri) ### Other [Section titled “Other”](#other-17) * add pr quality action ([e3905cf](https://github.com/pocket-id/pocket-id/commit/e3905cf3159fe0370778b0d7d3be64b4246d19be) by @stonith404) * bump google.golang.org/grpc from 1.79.1 to 1.79.3 in /backend in the go_modules group across 1 directory ([#1391](https://github.com/pocket-id/pocket-id/pull/1391) by @dependabot\[bot]) * Improve Latvian translations in lv.json ([#1382](https://github.com/pocket-id/pocket-id/pull/1382) by @Raito00) * ignore linter on app image bootstrap ([5251cd9](https://github.com/pocket-id/pocket-id/commit/5251cd97994177c96cb6f9ab3f88ca31367b5b55) by @kmendell) * upgrade dependencies ([e7e0176](https://github.com/pocket-id/pocket-id/commit/e7e0176316857186b9683e2f0cb0686189f86cfb) by @kmendell) * upgrade dependencies ([3c42a71](https://github.com/pocket-id/pocket-id/commit/3c42a713ce91b4061ffcf86d92cbb19294359ff8) by @kmendell) **Full Changelog**: ## v2.4.0 - 2026-03-07 [Section titled “v2.4.0 - 2026-03-07”](#v240---2026-03-07) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.4.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-17) * improve wildcard matching by using `go-urlpattern` ([#1332](https://github.com/pocket-id/pocket-id/pull/1332) by @stonith404) * federated client credentials not working if sub ≠ client_id ([#1342](https://github.com/pocket-id/pocket-id/pull/1342) by @ItalyPaleAle) * handle IPv6 addresses in callback URLs ([#1355](https://github.com/pocket-id/pocket-id/pull/1355) by @ItalyPaleAle) * wildcard callback URLs blocked by browser-native URL validation ([#1359](https://github.com/pocket-id/pocket-id/pull/1359) by @Copilot) * one-time-access-token route should get user ID from URL only ([#1358](https://github.com/pocket-id/pocket-id/pull/1358) by @ItalyPaleAle) * various fixes in background jobs ([#1362](https://github.com/pocket-id/pocket-id/pull/1362) by @ItalyPaleAle) * use URL keyboard type for callback URL inputs ([a675d07](https://github.com/pocket-id/pocket-id/commit/a675d075d1ab9b7ff8160f1cfc35bc0ea1f1980a) by @stonith404) ### Features [Section titled “Features”](#features-15) * allow first name and display name to be optional ([#1288](https://github.com/pocket-id/pocket-id/pull/1288) by @taoso) ### Other [Section titled “Other”](#other-18) * bump svelte from 5.53.2 to 5.53.5 in the npm_and_yarn group across 1 directory ([#1348](https://github.com/pocket-id/pocket-id/pull/1348) by @dependabot\[bot]) * bump @sveltejs/kit from 2.53.0 to 2.53.3 in the npm_and_yarn group across 1 directory ([#1349](https://github.com/pocket-id/pocket-id/pull/1349) by @dependabot\[bot]) * update AAGUIDs ([#1354](https://github.com/pocket-id/pocket-id/pull/1354) by @github-actions\[bot]) * add Português files ([01141b8](https://github.com/pocket-id/pocket-id/commit/01141b8c0f2e96a40fd876d3206e49a694fd12c4) by @kmendell) * add Latvian files ([e0fc4cc](https://github.com/pocket-id/pocket-id/commit/e0fc4cc01bd51e5a97e46aad78a493a668049220) by @kmendell) * fix wrong seed data ([e7bd66d](https://github.com/pocket-id/pocket-id/commit/e7bd66d1a77c89dde542b4385ba01dc0d432e434) by @stonith404) * fix wrong seed data in `database.json` ([f4eb8db](https://github.com/pocket-id/pocket-id/commit/f4eb8db50993edacd90e919b39a5c6d9dd4924c7) by @stonith404) ### Performance Improvements [Section titled “Performance Improvements”](#performance-improvements) * frontend performance optimizations ([#1344](https://github.com/pocket-id/pocket-id/pull/1344) by @ItalyPaleAle) **Full Changelog**: ## v2.3.0 - 2026-02-23 [Section titled “v2.3.0 - 2026-02-23”](#v230---2026-02-23) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.3.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-18) * ENCRYPTION_KEY needed for version and help commands ([#1256](https://github.com/pocket-id/pocket-id/pull/1256) by @kmendell) * prevent deletion of OIDC provider logo for non admin/anonymous users ([#1267](https://github.com/pocket-id/pocket-id/pull/1267) by @HiMoritz) * add `type="url"` to url inputs ([bb7b0d5](https://github.com/pocket-id/pocket-id/commit/bb7b0d56084df49b6a003cc3eaf076884e2cbf60) by @stonith404) * increase rate limit for frontend and api requests ([aab7e36](https://github.com/pocket-id/pocket-id/commit/aab7e364e85f1ce13950da93cc50324328cdd96d) by @stonith404) * decode URL-encoded client ID and secret in Basic auth ([#1263](https://github.com/pocket-id/pocket-id/pull/1263) by @ypomortsev) * token endpoint must not accept params as query string args ([#1321](https://github.com/pocket-id/pocket-id/pull/1321) by @ItalyPaleAle) * left align input error messages ([b3fe143](https://github.com/pocket-id/pocket-id/commit/b3fe14313684f9d8c389ed93ea8e479e3681b5c6) by @stonith404) * disallow API key renewal and creation with API key authentication ([#1334](https://github.com/pocket-id/pocket-id/pull/1334) by @stonith404) ### Features [Section titled “Features”](#features-16) * add VERSION_CHECK_DISABLED environment variable ([#1254](https://github.com/pocket-id/pocket-id/pull/1254) by @dihmandrake) * add support for HTTP/2 ([56afebc](https://github.com/pocket-id/pocket-id/commit/56afebc242be7ed14b58185425d6445bf18f640a) by @stonith404) * manageability of uncompressed geolite db file ([#1234](https://github.com/pocket-id/pocket-id/pull/1234) by @gucheen) * add JWT ID for generated tokens ([#1322](https://github.com/pocket-id/pocket-id/pull/1322) by @imnotjames) * current version api endpoint ([#1310](https://github.com/pocket-id/pocket-id/pull/1310) by @kmendell) ### Other [Section titled “Other”](#other-19) * bump @sveltejs/kit from 2.49.2 to 2.49.5 in the npm_and_yarn group across 1 directory ([#1240](https://github.com/pocket-id/pocket-id/pull/1240) by @dependabot\[bot]) * bump svelte from 5.46.1 to 5.46.4 in the npm_and_yarn group across 1 directory ([#1242](https://github.com/pocket-id/pocket-id/pull/1242) by @dependabot\[bot]) * bump devalue to 5.6.2 ([9dbc02e](https://github.com/pocket-id/pocket-id/commit/9dbc02e56871b2de6a39c443e1455efc26a949f7) by @kmendell) * upgrade deps ([4811625](https://github.com/pocket-id/pocket-id/commit/4811625cdd64b47ea67b7a9b03396e455896ccd6) by @kmendell) * add Estonian files ([53ef61a](https://github.com/pocket-id/pocket-id/commit/53ef61a3e5c4b77edec49d41ab94302bfec84269) by @kmendell) * update AAGUIDs ([#1257](https://github.com/pocket-id/pocket-id/pull/1257) by @github-actions\[bot]) * add Norwegian language files ([80558c5](https://github.com/pocket-id/pocket-id/commit/80558c562533e7b4d658d5baa4221d8cd209b47d) by @stonith404) * run formatter ([60825c5](https://github.com/pocket-id/pocket-id/commit/60825c5743b0e233ab622fd4d0ea04eb7ab59529) by @kmendell) * bump axios from 1.13.2 to 1.13.5 in the npm_and_yarn group across 1 directory ([#1309](https://github.com/pocket-id/pocket-id/pull/1309) by @dependabot\[bot]) * update dependenicies ([94a4897](https://github.com/pocket-id/pocket-id/commit/94a48977ba24e099b6221838d620c365eb1d4bf4) by @kmendell) * update AAGUIDs ([#1316](https://github.com/pocket-id/pocket-id/pull/1316) by @github-actions\[bot]) * bump svelte from 5.46.4 to 5.51.5 in the npm_and_yarn group across 1 directory ([#1324](https://github.com/pocket-id/pocket-id/pull/1324) by @dependabot\[bot]) * bump @sveltejs/kit from 2.49.5 to 2.52.2 in the npm_and_yarn group across 1 directory ([#1327](https://github.com/pocket-id/pocket-id/pull/1327) by @dependabot\[bot]) * upgrade dependencies ([0678699](https://github.com/pocket-id/pocket-id/commit/0678699d0cce5448c425b2c16bedab5fc242cbf0) by @stonith404) * upgrade to node 24 and go 1.26.0 ([#1328](https://github.com/pocket-id/pocket-id/pull/1328) by @kmendell) **Full Changelog**: ## v2.2.0 - 2026-01-11 [Section titled “v2.2.0 - 2026-01-11”](#v220---2026-01-11) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.2.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-19) * allow changing “require email address” if no SMTP credentials present ([8c68b08](https://github.com/pocket-id/pocket-id/commit/8c68b08c12ba371deda61662e3d048d63d07c56f) by @stonith404) * data import from sqlite to postgres fails because of wrong datatype ([1a032a8](https://github.com/pocket-id/pocket-id/commit/1a032a812ef78b250a898d14bec73a8ef7a7859a) by @stonith404) * user can’t update account if email is empty ([5828fa5](https://github.com/pocket-id/pocket-id/commit/5828fa57791314594625d52475733dce23cc2fcc) by @stonith404) * login codes sent by an admin incorrectly requires a device token ([03f9be0](https://github.com/pocket-id/pocket-id/commit/03f9be0d125732e02a8e2c5390d9e6d0c74ce957) by @stonith404) * allow exchanging logic code if already authenticated ([0e2cdc3](https://github.com/pocket-id/pocket-id/commit/0e2cdc393e34276bb3b8ea318cdc7261de3f2dec) by @stonith404) * db version downgrades don’t downgrade db schema ([4df4bcb](https://github.com/pocket-id/pocket-id/commit/4df4bcb6451b4bf88093e04f3222c8737f2c7be3) by @stonith404) ### Features [Section titled “Features”](#features-17) * add CLI command for encryption key rotation ([#1209](https://github.com/pocket-id/pocket-id/pull/1209) by @stonith404) * improve passkey error messages ([2f25861](https://github.com/pocket-id/pocket-id/commit/2f25861d15aefa868042e70d3e21b7b38a6ae679) by @stonith404) * make home page URL configurable ([#1215](https://github.com/pocket-id/pocket-id/pull/1215) by @stonith404) * add option to renew API key ([#1214](https://github.com/pocket-id/pocket-id/pull/1214) by @stonith404) * add support for email verification ([#1223](https://github.com/pocket-id/pocket-id/pull/1223) by @stonith404) * add environment variable to disable built-in rate limiting ([9ca3d33](https://github.com/pocket-id/pocket-id/commit/9ca3d33c8897cf49a871783058205bb180529cd2) by @stonith404) * add static api key env variable ([#1229](https://github.com/pocket-id/pocket-id/pull/1229) by @stonith404) **Full Changelog**: ## v2.1.0 - 2026-01-04 [Section titled “v2.1.0 - 2026-01-04”](#v210---2026-01-04) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.1.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-20) * invalid cookie name for email login code device token ([d6a7b50](https://github.com/pocket-id/pocket-id/commit/d6a7b503ff4571b1291a55a569add3374f5e2d5b) by @stonith404) ### Features [Section titled “Features”](#features-18) * add issuer url to oidc client details list ([#1197](https://github.com/pocket-id/pocket-id/pull/1197) by @kmendell) * process nonce within device authorization flow ([#1185](https://github.com/pocket-id/pocket-id/pull/1185) by @justincmoy) ### Other [Section titled “Other”](#other-20) * run SCIM jobs in context of gocron instead of custom implementation ([4881130](https://github.com/pocket-id/pocket-id/commit/4881130eadcef0642f8a87650b7c36fda453b51b) by @stonith404) **Full Changelog**: ## v2.0.2 - 2026-01-03 [Section titled “v2.0.2 - 2026-01-03”](#v202---2026-01-03) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.0.2) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-21) * migration fails if users exist with no email address ([2f651ad](https://github.com/pocket-id/pocket-id/commit/2f651adf3b4e8d689461da2083c3afcb1eb1d477) by @stonith404) * allow version downgrade if database is dirty ([ba00f40](https://github.com/pocket-id/pocket-id/commit/ba00f40bd4b06f31d251599fcb1db63e902a6987) by @stonith404) * localhost callback URLs with port don’t match correctly ([7c34501](https://github.com/pocket-id/pocket-id/commit/7c345010556f11a593948b2a1ae558b7a8003696) by @stonith404) ### Other [Section titled “Other”](#other-21) * add no-op migration to postgres ([a24b2af](https://github.com/pocket-id/pocket-id/commit/a24b2afb7b8165bed05976058a8ae797adc245df) by @stonith404) **Full Changelog**: ## v2.0.1 - 2026-01-02 [Section titled “v2.0.1 - 2026-01-02”](#v201---2026-01-02) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.0.1) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-22) * admins imported from LDAP lose admin privileges ([2cce200](https://github.com/pocket-id/pocket-id/commit/2cce2008928081b5e0f0e6bcbc3f43816f082de9) by @stonith404) * restore old input input field size ([2341da9](https://github.com/pocket-id/pocket-id/commit/2341da99e9716686cf28dd0680d751ae9da0fadc) by @stonith404) ### Other [Section titled “Other”](#other-22) * bump image tag to `v2` ([cd2e9f3](https://github.com/pocket-id/pocket-id/commit/cd2e9f3a2ad753815ef8da998f9b54853d953a2a) by @stonith404) **Full Changelog**: ## v2.0.0 - 2026-01-02 [Section titled “v2.0.0 - 2026-01-02”](#v200---2026-01-02) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v2.0.0) Caution This is a major release which includes some breaking changes, please follow the [migration guide](https://pocket-id.org/docs/setup/major-releases/migrate-v2) to upgrade to `v2`. ### Features [Section titled “Features”](#features-19) * add support for SCIM provisioning ([#1182](https://github.com/pocket-id/pocket-id/pull/1182) by @stonith404) * add CLI command for importing and exporting Pocket ID data ([3420a00](https://github.com/pocket-id/pocket-id/commit/3420a000737d89a5c3c6c250d171d96126553beb) by @stonith404) * add HTTP `HEAD` method support ([#1135](https://github.com/pocket-id/pocket-id/pull/1135) by @stonith404) * add email logo customization ([#1150](https://github.com/pocket-id/pocket-id/pull/1150) by @MelvinSnijders) * add ability define user groups for sign up tokens ([#1155](https://github.com/pocket-id/pocket-id/pull/1155) by @stonith404) * minor redesign of auth pages ([08e4ffe](https://github.com/pocket-id/pocket-id/commit/08e4ffeb600a4a6644d91b1600b0205997ed1685) by @stonith404) * allow audit log retention to be controlled by env variable ([#1158](https://github.com/pocket-id/pocket-id/pull/1158) by @jenic) * restrict oidc clients by user groups per default ([#1164](https://github.com/pocket-id/pocket-id/pull/1164) by @stonith404) * add “restricted” column to oidc client table ([1bc9f5f](https://github.com/pocket-id/pocket-id/commit/1bc9f5f7e780310d81608381544ba530df7f433b) by @stonith404) * drop support for storing JWK on the filesystem ([f014458](https://github.com/pocket-id/pocket-id/commit/f0144584af90b918a3157a298f1bb95928a117b8) by @stonith404) * remove DbProvider env variable and calculate it dynamically ([ba2f0f1](https://github.com/pocket-id/pocket-id/commit/ba2f0f18f4bacc5a86217dec0b0dcb6030c40cb9) by @kmendell) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-23) * update image format message to include WEBP ([#1133](https://github.com/pocket-id/pocket-id/pull/1133) by @sebdanielsson) * add Japanese locale to inlang settings ([#1142](https://github.com/pocket-id/pocket-id/pull/1142) by @tai-ga) * restrict email one time sign in token to same browser ([#1144](https://github.com/pocket-id/pocket-id/pull/1144) by @stonith404) * rename `LDAP_ATTRIBUTE_ADMIN_GROUP` env variable to `LDAP_ADMIN_GROUP_NAME` ([e1c5021](https://github.com/pocket-id/pocket-id/commit/e1c5021eeedcbc54bad0eccd72d7ae760be61934) by @stonith404) * make wildcard matching in callback URLs more stricter ([078152d](https://github.com/pocket-id/pocket-id/commit/078152d4dbb05dd027ff323f39d090ecb67927c7) by @stonith404) * remove ambiguous characters from login code ([d9e7bf9](https://github.com/pocket-id/pocket-id/commit/d9e7bf9eef522d8c081fac2000bace6f95518039) by @stonith404) * add missing translations to date picker ([894eaf3](https://github.com/pocket-id/pocket-id/commit/894eaf3cffdd9182b9c29e28b4dcb7e8bcbda26b) by @stonith404) ### Other [Section titled “Other”](#other-23) * update AAGUIDs ([#1128](https://github.com/pocket-id/pocket-id/pull/1128) by @github-actions\[bot]) * fix api key e2e test ([25f67bd](https://github.com/pocket-id/pocket-id/commit/25f67bd25a0ee0cab48d72107722e8c8428fa547) by @stonith404) * update AAGUIDs ([#1140](https://github.com/pocket-id/pocket-id/pull/1140) by @github-actions\[bot]) * upgrade dependencies ([90f555f](https://github.com/pocket-id/pocket-id/commit/90f555f7c12ff07545f7cd1a1754a8c19f5a4978) by @stonith404) * fix type error after version bump ([edb32d8](https://github.com/pocket-id/pocket-id/commit/edb32d82b2c138433d8eb17d5a6a19f4728ae2d4) by @stonith404) * remove `breaking/**` push trigger from actions ([461293b](https://github.com/pocket-id/pocket-id/commit/461293ba1da4ddbff2c77f23a42487b63964e474) by @stonith404) * update AAGUIDs ([#1177](https://github.com/pocket-id/pocket-id/pull/1177) by @github-actions\[bot]) * preparation for merge into main branch ([#1113](https://github.com/pocket-id/pocket-id/pull/1113) by @stonith404) * bump pnpm to version 10.27.0 ([#1183](https://github.com/pocket-id/pocket-id/pull/1183) by @kmendell) * update forms and other areas to use new shadcn components ([#1115](https://github.com/pocket-id/pocket-id/pull/1115) by @kmendell) * run formatter ([e4a8ca4](https://github.com/pocket-id/pocket-id/commit/e4a8ca476cc3c7e8d8cdc8de21b5d7d99d07f7a0) by @stonith404) * upgrade dependencies ([4776b70](https://github.com/pocket-id/pocket-id/commit/4776b70d96f3dc291394dc79c941738bbe48199a) by @stonith404) * change translation string in e2e tests ([ffb2ef9](https://github.com/pocket-id/pocket-id/commit/ffb2ef91bd7bbe78eb29e86cd3675b695e821498) by @stonith404) **Full Changelog**: ## v1.16.0 - 2025-11-30 [Section titled “v1.16.0 - 2025-11-30”](#v1160---2025-11-30) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.16.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-24) * use `quoted-printable` encoding for mails to prevent line limitation ([5cf73e9](https://github.com/pocket-id/pocket-id/commit/5cf73e9309640d097ba94d97851cf502b7b2e063) by @stonith404) * automatically create parent directory of Sqlite db ([cfc9e46](https://github.com/pocket-id/pocket-id/commit/cfc9e464d983b051e7ed4da1620fae61dc73cff2) by @stonith404) * global audit log user filter not working ([d98c0a3](https://github.com/pocket-id/pocket-id/commit/d98c0a391a747f9eea70ea01c3f984264a4a7a19) by @stonith404) * theme mode not correctly applied if selected manually ([a1cd325](https://github.com/pocket-id/pocket-id/commit/a1cd3251cd2b7d7aca610696ef338c5d01fdce2e) by @stonith404) * hide theme switcher on auth pages because of dynamic background ([5d6a7fd](https://github.com/pocket-id/pocket-id/commit/5d6a7fdb58b6b82894dcb9be3b9fe6ca3e53f5fa) by @stonith404) ### Documentation [Section titled “Documentation”](#documentation-8) * add `ENCRYPTION_KEY` to `.env.example` for breaking change preparation ([4eeb06f](https://github.com/pocket-id/pocket-id/commit/4eeb06f29d984164939bf66299075efead87ee19) by @stonith404) ### Features [Section titled “Features”](#features-20) * light/dark/system mode switcher ([#1081](https://github.com/pocket-id/pocket-id/pull/1081) by @kmendell) * add support for S3 storage backend ([#1080](https://github.com/pocket-id/pocket-id/pull/1080) by @stonith404) * add support for WEBP profile pictures ([#1090](https://github.com/pocket-id/pocket-id/pull/1090) by @stonith404) * add database storage backend ([#1091](https://github.com/pocket-id/pocket-id/pull/1091) by @ItalyPaleAle) * adding/removing passkeys creates an entry in audit logs ([#1099](https://github.com/pocket-id/pocket-id/pull/1099) by @ItalyPaleAle) * add option to disable S3 integrity check ([a3c9687](https://github.com/pocket-id/pocket-id/commit/a3c968758a17e95b2e55ae179d6601d8ec2cf052) by @stonith404) * add `Cache-Control: private, no-store` to all API routes per default ([#1126](https://github.com/pocket-id/pocket-id/pull/1126) by @stonith404) ### Other [Section titled “Other”](#other-24) * update pnpm to 10.20 ([#1082](https://github.com/pocket-id/pocket-id/pull/1082) by @kmendell) * run checks on PR to `breaking/**` branches ([ab9c0f9](https://github.com/pocket-id/pocket-id/commit/ab9c0f9ac092725c70ec3a963f57bc739f425d4f) by @stonith404) * use constants for AppEnv values ([#1098](https://github.com/pocket-id/pocket-id/pull/1098) by @ItalyPaleAle) * bump golang.org/x/crypto from 0.43.0 to 0.45.0 in /backend in the go_modules group across 1 directory ([#1107](https://github.com/pocket-id/pocket-id/pull/1107) by @dependabot\[bot]) * add Finish files ([ca888b3](https://github.com/pocket-id/pocket-id/commit/ca888b3dd221a209df5e7beb749156f7ea21e1c0) by @stonith404) * upgrade dependencies ([4bde271](https://github.com/pocket-id/pocket-id/commit/4bde271b4715f59bd2ed1f7c18a867daf0f26b8b) by @stonith404) * fix Dutch validation message ([f523f39](https://github.com/pocket-id/pocket-id/commit/f523f39483a06256892d17dc02528ea009c87a9f) by @stonith404) * fix package vulnerabilities ([3d46bad](https://github.com/pocket-id/pocket-id/commit/3d46badb3cecc1ee8eb8bfc9b377108be32d4ffc) by @stonith404) * update vscode launch.json ([#1117](https://github.com/pocket-id/pocket-id/pull/1117) by @mnestor) * rename file backend value `fs` to `filesystem` ([8d30346](https://github.com/pocket-id/pocket-id/commit/8d30346f642b483653f7a3dec006cb0273927afb) by @stonith404) * fix wrong storage value ([b2c718d](https://github.com/pocket-id/pocket-id/commit/b2c718d13d12b6c152e19974d3490c2ed7f5d51d) by @stonith404) * run formatter ([14c7471](https://github.com/pocket-id/pocket-id/commit/14c7471b5272cdaf42751701d842348d0d60cd0e) by @stonith404) **Full Changelog**: ## v1.15.0 - 2025-11-06 [Section titled “v1.15.0 - 2025-11-06”](#v1150---2025-11-06) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.15.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-25) * sorting by PKCE and re-auth of OIDC clients ([e03270e](https://github.com/pocket-id/pocket-id/commit/e03270eb9d474735ff4a1b4d8c90f1857b8cd52b) by @stonith404) * replace %lang% placeholder in html lang ([#1071](https://github.com/pocket-id/pocket-id/pull/1071) by @daimond113) * disabled property gets ignored when creating an user ([76e0192](https://github.com/pocket-id/pocket-id/commit/76e0192ceec339b6ddb4ad3424057d2bb48fae8f) by @stonith404) * remove redundant indexes in Postgres ([6a038fc](https://github.com/pocket-id/pocket-id/commit/6a038fcf9afabbf00c45e42071e9bbe62ecab403) by @stonith404) ### Features [Section titled “Features”](#features-21) * open edit page on table row click ([f184120](https://github.com/pocket-id/pocket-id/commit/f184120890c32f1e75a918c171084878a10e8b42) by @stonith404) * add ability to set default profile picture ([#1061](https://github.com/pocket-id/pocket-id/pull/1061) by @stonith404) ### Other [Section titled “Other”](#other-25) * add support for OpenBSD binaries ([d683d18](https://github.com/pocket-id/pocket-id/commit/d683d18d9109ca2850e278b78f7bf3e5aca1d34d) by @stonith404) **Full Changelog**: ## v1.14.2 - 2025-10-29 [Section titled “v1.14.2 - 2025-10-29”](#v1142---2025-10-29) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.14.2) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-26) * dark oidc client icons not saved on client creation ([#1057](https://github.com/pocket-id/pocket-id/pull/1057) by @mufeedali) ### Other [Section titled “Other”](#other-26) * add Turkish language files ([a190529](https://github.com/pocket-id/pocket-id/commit/a190529117fe20b5b836d452b382da69abba9458) by @stonith404) **Full Changelog**: ## v1.14.1 - 2025-10-27 [Section titled “v1.14.1 - 2025-10-27”](#v1141---2025-10-27) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.14.1) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-27) * Prevent blinding FOUC in dark mode ([#1054](https://github.com/pocket-id/pocket-id/pull/1054) by @mufeedali) * use credProps to save passkey on firefox android ([#1055](https://github.com/pocket-id/pocket-id/pull/1055) by @lhoursquentin) * ignore trailing slashes in `APP_URL` ([65616f6](https://github.com/pocket-id/pocket-id/commit/65616f65e53f3e62d18a8209929e68ddc8d2b9b8) by @stonith404) **Full Changelog**: ## v1.14.0 - 2025-10-24 [Section titled “v1.14.0 - 2025-10-24”](#v1140---2025-10-24) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.14.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-28) * ignore trailing slash in URL ([9f0aa55](https://github.com/pocket-id/pocket-id/commit/9f0aa55be67b7a09810569250563bb388b40590a) by @stonith404) * use constant time comparisons when validating PKCE challenges ([#1047](https://github.com/pocket-id/pocket-id/pull/1047) by @ItalyPaleAle) * only animate login background on initial page load ([b356cef](https://github.com/pocket-id/pocket-id/commit/b356cef766697c621157235ae1d2743f3fe6720d) by @stonith404) * make pkce requirement visible in the oidc form if client is public ([47927d1](https://github.com/pocket-id/pocket-id/commit/47927d157470daa5b5a5b30e61a2ba69110eeff9) by @stonith404) * prevent page flickering on redirection based on auth state ([10d6403](https://github.com/pocket-id/pocket-id/commit/10d640385ff2078299a07f05e5ca3f0d392eecf7) by @stonith404) ### Features [Section titled “Features”](#features-22) * add various improvements to the table component ([#961](https://github.com/pocket-id/pocket-id/pull/961) by @stonith404) * add support for dark mode oidc client icons ([#1039](https://github.com/pocket-id/pocket-id/pull/1039) by @kmendell) ### Other [Section titled “Other”](#other-27) * add Japanese files ([068fcc6](https://github.com/pocket-id/pocket-id/commit/068fcc65a62c76f55c9636f830fc769bd59220c4) by @kmendell) * bump sveltekit-superforms from 2.27.1 to 2.27.4 in the npm_and_yarn group across 1 directory ([#1031](https://github.com/pocket-id/pocket-id/pull/1031) by @dependabot\[bot]) * update AAGUIDs ([#1041](https://github.com/pocket-id/pocket-id/pull/1041) by @github-actions\[bot]) * bump vite from 7.0.7 to 7.0.8 in the npm_and_yarn group across 1 directory ([#1042](https://github.com/pocket-id/pocket-id/pull/1042) by @dependabot\[bot]) * upgrade dependencies ([6362ff9](https://github.com/pocket-id/pocket-id/commit/6362ff986124d056cc07d214855f198eab9cb97d) by @stonith404) **Full Changelog**: ## v1.13.1 - 2025-10-07 [Section titled “v1.13.1 - 2025-10-07”](#v1131---2025-10-07) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.13.1) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-29) * uploading a client logo with an URL fails ([#1008](https://github.com/pocket-id/pocket-id/pull/1008) by @CzBiX) * mark any callback url as valid if they contain a wildcard ([#1006](https://github.com/pocket-id/pocket-id/pull/1006) by @stonith404) ### Other [Section titled “Other”](#other-28) * cleanup root of repo, update workflow actions ([#1003](https://github.com/pocket-id/pocket-id/pull/1003) by @kmendell) **Full Changelog**: ## v1.13.0 - 2025-10-05 [Section titled “v1.13.0 - 2025-10-05”](#v1130---2025-10-05) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.13.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-30) * uploading a client logo with an URL fails if folder doesn’t exist ([ad8a90c](https://github.com/pocket-id/pocket-id/commit/ad8a90c839cc79b542b60ae66c7eb9254fa5f3e4) by @stonith404) ### Features [Section titled “Features”](#features-23) * add link to API docs on API key page ([2c74865](https://github.com/pocket-id/pocket-id/commit/2c74865173344766bd43ffd6ae6d93d564de47c7) by @stonith404) **Full Changelog**: ## v1.12.0 - 2025-10-03 [Section titled “v1.12.0 - 2025-10-03”](#v1120---2025-10-03) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.12.0) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-31) * do not use cache=shared for in-memory SQLite ([#971](https://github.com/pocket-id/pocket-id/pull/971) by @ItalyPaleAle) * show only country in audit log location if no city instead of Unknown ([#977](https://github.com/pocket-id/pocket-id/pull/977) by @vilisseranen) * display login location correctly if country or city is not present ([79989fb](https://github.com/pocket-id/pocket-id/commit/79989fb176273cef070dc52c338004b443364db8) by @stonith404) * remove previous socket file to prevent bind error ([#979](https://github.com/pocket-id/pocket-id/pull/979) by @Caian) * tokens issued with refresh token flow don’t contain groups ([#989](https://github.com/pocket-id/pocket-id/pull/989) by @ItalyPaleAle) * make logo and oidc client images sizes consistent ([01db8c0](https://github.com/pocket-id/pocket-id/commit/01db8c0a46b69a15a40951ba863e6bc08fa8e1f8) by @stonith404) * include port in OIDC client details ([2c1c67b](https://github.com/pocket-id/pocket-id/commit/2c1c67b5e403b365204854c5eb222a68236f3ce0) by @stonith404) * prevent endless effect loop in login wrapper ([fc9939d](https://github.com/pocket-id/pocket-id/commit/fc9939d1f1817c0b014cc54e6525b98762835295) by @stonith404) * improve back button handling on auth pages ([d47b203](https://github.com/pocket-id/pocket-id/commit/d47b20326f96b6fff405fcc211719bf3068085ee) by @stonith404) * allow any image source but disallow base64 ([22f4254](https://github.com/pocket-id/pocket-id/commit/22f42549323fde8b9eaeff682bfa4c7f27e05526) by @stonith404) * date locale can’t be loaded if locale is `en` ([b81de45](https://github.com/pocket-id/pocket-id/commit/b81de451668c425bfc5ca7cd6071fe2756b31594) by @stonith404) ### Features [Section titled “Features”](#features-24) * support for url based icons ([#840](https://github.com/pocket-id/pocket-id/pull/840) by @kmendell) * hide alternative sign in methods page if email login disabled ([d010be4](https://github.com/pocket-id/pocket-id/commit/d010be4c8804153b4a7f55bd4ea1cedb0df471df) by @stonith404) * add required indicator for required inputs ([#993](https://github.com/pocket-id/pocket-id/pull/993) by @stonith404) * add the ability to make email optional ([#994](https://github.com/pocket-id/pocket-id/pull/994) by @stonith404) ### Other [Section titled “Other”](#other-29) * fix whitespace after commit message ([e8b172f](https://github.com/pocket-id/pocket-id/commit/e8b172f1c3df8eca8f463d7fa25a483b90a7e66c) by @stonith404) * update AAGUIDs ([#972](https://github.com/pocket-id/pocket-id/pull/972) by @github-actions\[bot]) * remove unnecessary logo fallback ([b746ac0](https://github.com/pocket-id/pocket-id/commit/b746ac0835da059e747a829df3a74e1eae79e107) by @stonith404) ### Sponsors [Section titled “Sponsors”](#sponsors) Thanks @paradosi for your tip ❤️ **Full Changelog**: ## v1.11.2 - 2025-09-20 [Section titled “v1.11.2 - 2025-09-20”](#v1112---2025-09-20) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.11.2) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-32) * embedded paths not found on windows ([c55143d](https://github.com/pocket-id/pocket-id/commit/c55143d8c995fcd604edcdd448c50669e8682e33) by @stonith404) * do not treat certain failures in app images bootstrap as fatal ([#966](https://github.com/pocket-id/pocket-id/pull/966) by @ItalyPaleAle) * decouple images from app config service ([#965](https://github.com/pocket-id/pocket-id/pull/965) by @stonith404) ### Other [Section titled “Other”](#other-30) * use git cliff for release notes ([fde4e9b](https://github.com/pocket-id/pocket-id/commit/fde4e9b38a34331137a64ce328dad6faf9885808) by @stonith404) **Full Changelog**: ## v1.11.1 - 2025-09-18 [Section titled “v1.11.1 - 2025-09-18”](#v1111---2025-09-18) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.11.1) Note This release adds missing translations for `v1.11.0` because I forgot to merge the PR before creating the release. See the release notes for `v1.11.0` [here](https://github.com/pocket-id/pocket-id/releases/tag/v1.11.0). ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-33) * add missing translations ([8c9cac2](https://github.com/pocket-id/pocket-id/commit/8c9cac2655ddbe4872234a1b55fdd51d2f3ac31c)) ## v1.11.0 - 2025-09-18 [Section titled “v1.11.0 - 2025-09-18”](#v1110---2025-09-18) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.11.0) ### Features [Section titled “Features”](#features-25) * add CSP header ([#908](https://github.com/pocket-id/pocket-id/issues/908)) ([6215e1a](https://github.com/pocket-id/pocket-id/commit/6215e1ac01c03866f8b2e89ac084ddd6a3c3ac9e)) * add `INTERNAL_APP_URL` env variable ([#858](https://github.com/pocket-id/pocket-id/issues/858) by @DerSteph) * add info box to app settings if UI config is disabled ([a1d8538](https://github.com/pocket-id/pocket-id/commit/a1d8538c64beb4d7e8559934985772fba27623ca)) * add PWA support ([#938](https://github.com/pocket-id/pocket-id/issues/938)) ([5367463](https://github.com/pocket-id/pocket-id/commit/5367463239b354640fd65390bc409e4a0ac13fd1)) * add support for `LOG_LEVEL` env variable ([#942](https://github.com/pocket-id/pocket-id/issues/942)) ([2d6d5df](https://github.com/pocket-id/pocket-id/commit/2d6d5df0e7f104a148fb4eeac89a2fbb7db8047a)) * add user display name field ([#898](https://github.com/pocket-id/pocket-id/issues/898)) ([6837360](https://github.com/pocket-id/pocket-id/commit/68373604dd30065947226922233bc1e19e778b01)) * allow uppercase usernames ([#958](https://github.com/pocket-id/pocket-id/issues/958)) ([0224949](https://github.com/pocket-id/pocket-id/commit/02249491f86c289adf596d9d9922dfa04779edee)) * client_credentials flow support ([#901](https://github.com/pocket-id/pocket-id/issues/901) by @savely-krasovsky) * return new id_token when using refresh token ([#925](https://github.com/pocket-id/pocket-id/issues/925)) ([307caaa](https://github.com/pocket-id/pocket-id/commit/307caaa3efbc966341b95ee4b5ff18c81ed98e54)) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-34) * add validation for callback URLs ([#929](https://github.com/pocket-id/pocket-id/issues/929)) ([6c91474](https://github.com/pocket-id/pocket-id/commit/6c9147483c0a370e2b5011d13898279d2acc445d)) * disable sign up options in UI if `UI_CONFIG_DISABLED` ([1d7cbc2](https://github.com/pocket-id/pocket-id/commit/1d7cbc2a4ecf352d46087f30b477f6bbaa23adf5)) * ensure users imported from LDAP have fields validated ([#923](https://github.com/pocket-id/pocket-id/issues/923)) ([4215523](https://github.com/pocket-id/pocket-id/commit/42155238b750b015b0547294f397e1e285594e3e)) * key-rotate doesn’t work with database storage ([#940](https://github.com/pocket-id/pocket-id/issues/940)) ([c018f29](https://github.com/pocket-id/pocket-id/commit/c018f29ad7c61a3ef1b235b0d404a3a2024a26ca)) * list items on previous page get unselected if other items selected on next page ([6c696b4](https://github.com/pocket-id/pocket-id/commit/6c696b46c8b60b3dc4af35c9c6cf1b8e1322f4cd)) * make environment variables case insensitive where necessary ([#954](https://github.com/pocket-id/pocket-id/issues/954)) ([99f31a7](https://github.com/pocket-id/pocket-id/commit/99f31a7c26c63dec76682ddf450d88e6ee40876f)) * my apps card shouldn’t take full width if only one item exists ([e7e53a8](https://github.com/pocket-id/pocket-id/commit/e7e53a8b8c87bee922167d24556aef3ea219b1a2)) * update localized name and description of ldap group name attribute ([#892](https://github.com/pocket-id/pocket-id/issues/892)) ([e88be7e](https://github.com/pocket-id/pocket-id/commit/e88be7e61a8aafabcae70adf9265023c50626705)) ### Sponsors [Section titled “Sponsors”](#sponsors-1) Thank you @Felitendo very much for your tip! ## v1.10.0 - 2025-08-27 [Section titled “v1.10.0 - 2025-08-27”](#v1100---2025-08-27) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.10.0) ### Features [Section titled “Features”](#features-26) * redesigned sidebar with administrative dropdown ([#881](https://github.com/pocket-id/pocket-id/issues/881)) ([096d214](https://github.com/pocket-id/pocket-id/commit/096d214a88808848dae726b0ef4c9a9987185836)) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-35) * apps showed multiple times if user is in multiple groups ([641bbc9](https://github.com/pocket-id/pocket-id/commit/641bbc935191bad8afbfec90943fc3e9de7a0cb6)) ## v1.9.1 - 2025-08-24 [Section titled “v1.9.1 - 2025-08-24”](#v191---2025-08-24) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.9.1) Caution A bug was introduced in `v1.8.0` that caused the deletion of all allowed user groups on OIDC clients. It is highly recommended to check if the allowed user groups are still in place. If they are not, unfortunately, the deleted relations cannot be restored automatically. You will need to either restore them from a backup or recreate them manually. You can learn more about the cause in this [comment](https://github.com/pocket-id/pocket-id/issues/865#issuecomment-3218287796). ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-36) * sqlite migration drops allowed user groups ([d6d1a4c](https://github.com/pocket-id/pocket-id/commit/d6d1a4ced23886f255a9c2048d19ad3599a17f26)) ## v1.9.0 - 2025-08-24 [Section titled “v1.9.0 - 2025-08-24”](#v190---2025-08-24) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.9.0) ### Features [Section titled “Features”](#features-27) * support automatic db migration rollbacks ([#874](https://github.com/pocket-id/pocket-id/issues/874)) ([c114a2e](https://github.com/pocket-id/pocket-id/commit/c114a2edaae4c007c75c34c02e8b0bb011845cae)) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-37) * don’t force uuid for client id in postgres ([2ffc6ba](https://github.com/pocket-id/pocket-id/commit/2ffc6ba42af4742a13b77543142b66b3e826ab88)) * ensure SQLite has a writable temporary directory ([#876](https://github.com/pocket-id/pocket-id/issues/876)) ([1f3550c](https://github.com/pocket-id/pocket-id/commit/1f3550c9bd3aafd3bd2272ef47f3ed8736037d81)) * sort order incorrect for apps when using postgres ([d0392d2](https://github.com/pocket-id/pocket-id/commit/d0392d25edcaa5f3c7da2aad70febf63b47763fa)) ## v1.8.1 - 2025-08-24 [Section titled “v1.8.1 - 2025-08-24”](#v181---2025-08-24) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.8.1) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-38) * migration clears allowed users groups ([5971bfb](https://github.com/pocket-id/pocket-id/commit/5971bfbfa66ecfebf2b1c08d34fcbd8c18cdc046)) * wrong column type for reauthentication tokens in Postgres ([#869](https://github.com/pocket-id/pocket-id/issues/869)) ([1283314](https://github.com/pocket-id/pocket-id/commit/1283314f776a0ba43be7d796e7e2243e31f860de)) ## v1.8.0 - 2025-08-23 [Section titled “v1.8.0 - 2025-08-23”](#v180---2025-08-23) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.8.0) ### Features [Section titled “Features”](#features-28) * add option to OIDC client to require re-authentication ([#747](https://github.com/pocket-id/pocket-id/issues/747) by @MorrisMorrison) ([0cb039d](https://github.com/pocket-id/pocket-id/commit/0cb039d35d49206011064e622f3bfd3d8f88720f)) * allow custom client IDs ([#864](https://github.com/pocket-id/pocket-id/issues/864) thanks to @James18232) ([a5efb95](https://github.com/pocket-id/pocket-id/commit/a5efb9506582884c70b9b1fd737ebdd44b101b47)) * display all accessible oidc clients in the dashboard ([#832](https://github.com/pocket-id/pocket-id/issues/832)) ([3188e92](https://github.com/pocket-id/pocket-id/commit/3188e92257afcaf7a16dd418e4c40626d7e1d034)) * login code font change ([#851](https://github.com/pocket-id/pocket-id/issues/851) by @James18232) ([d28bfac](https://github.com/pocket-id/pocket-id/commit/d28bfac81fc24ee79e4896538a616f0a89ab30a5)) * **signup:** add default user groups and claims for new users ([#812](https://github.com/pocket-id/pocket-id/issues/812) by @zeedif) ([182d809](https://github.com/pocket-id/pocket-id/commit/182d8090286f9953171c6c410283be679889aca7)) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-39) * authorization can’t be revoked ([0aab3f3](https://github.com/pocket-id/pocket-id/commit/0aab3f3c7ad8c1b14939de3ded60c9f201eab8fc)) * delete webauthn session after login to prevent replay attacks ([fe003b9](https://github.com/pocket-id/pocket-id/commit/fe003b927ce7772692439992860c804de89ce424)) * **deps:** bump rollup from 4.45.3 to 4.46.3 ([#845](https://github.com/pocket-id/pocket-id/issues/845) by @gepbird) ([b5e6371](https://github.com/pocket-id/pocket-id/commit/b5e6371eaaf3d9e85d8b05c457487c4425fa8381)) * enable foreign key check for sqlite ([#863](https://github.com/pocket-id/pocket-id/issues/863)) ([625f235](https://github.com/pocket-id/pocket-id/commit/625f23574001ebd7074b8d98d448a2811847be16)) * ferated identities can’t be cleared ([24e2742](https://github.com/pocket-id/pocket-id/commit/24e274200fe4002d01c58cc3fa74094b598d7599)) * for one-time access tokens and signup tokens, pass TTLs instead of absolute expiration date ([#855](https://github.com/pocket-id/pocket-id/issues/855)) ([7ab0fd3](https://github.com/pocket-id/pocket-id/commit/7ab0fd30286e6b67b5ce586484d82a20c42b471d)) * ignore client secret if client is public ([#836](https://github.com/pocket-id/pocket-id/issues/836) by @James18232) ([7b1f6b8](https://github.com/pocket-id/pocket-id/commit/7b1f6b88572bac1f3e838a9e904917fbd5fbdf61)) * move audit log call before TX is committed ([#854](https://github.com/pocket-id/pocket-id/issues/854)) ([9339e88](https://github.com/pocket-id/pocket-id/commit/9339e88a5a26ff77a5e40149cbb1a5b339b7ec6a)) * non admin users can’t revoke oidc client but see edit link ([0e44f24](https://github.com/pocket-id/pocket-id/commit/0e44f245afcdf8179bf619613ca9ef4bffa176ca)) * oidc client advanced options color ([fc0c99a](https://github.com/pocket-id/pocket-id/commit/fc0c99a232b0efb1a5b5d2c551102418b1080293)) ### Sponsors [Section titled “Sponsors”](#sponsors-2) Thanks Brandon Butler (@Starttoaster) for your support! ## v1.7.0 - 2025-08-10 [Section titled “v1.7.0 - 2025-08-10”](#v170---2025-08-10) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.7.0) ### Features [Section titled “Features”](#features-29) * add robots.txt to block indexing ([#806](https://github.com/pocket-id/pocket-id/issues/806) by @Etienne-bdt) ([06e1656](https://github.com/pocket-id/pocket-id/commit/06e1656923eb2f4531be497716f9147c09d60b65)) * add support for `code_challenge_methods_supported` ([#794](https://github.com/pocket-id/pocket-id/issues/794)) ([d479817](https://github.com/pocket-id/pocket-id/commit/d479817b6a7ca4807b5de500b3ba713d436b0770)) * Support OTel and JSON for logs (via log/slog) ([#760](https://github.com/pocket-id/pocket-id/issues/760)) ([78266e3](https://github.com/pocket-id/pocket-id/commit/78266e3e4cab2b23249c3baf20f4387d00eebd9e)) * support reading secret env vars from \_FILE ([#799](https://github.com/pocket-id/pocket-id/issues/799)) ([0a3b1c6](https://github.com/pocket-id/pocket-id/commit/0a3b1c653050f2237d30ec437c5de88baa704a25)) * user application dashboard ([#727](https://github.com/pocket-id/pocket-id/issues/727)) ([484c2f6](https://github.com/pocket-id/pocket-id/commit/484c2f6ef20efc1fade1a41e2aeace54c7bb4f1b)) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-40) * admins can not delete or disable their own account ([f0c144c](https://github.com/pocket-id/pocket-id/commit/f0c144c51c635bc348222a00d3bc88bc4e0711ef)) * authorization animation not working ([9ac5d51](https://github.com/pocket-id/pocket-id/commit/9ac5d5118710cad59c8c4ce7cef7ab09be3de664)) * custom claims input suggestions instantly close after opening ([4d59e72](https://github.com/pocket-id/pocket-id/commit/4d59e7286666480e20c728787a95e82513509240)) * delete WebAuthn registration session after use ([#783](https://github.com/pocket-id/pocket-id/issues/783)) ([c8478d7](https://github.com/pocket-id/pocket-id/commit/c8478d75bed7295625cd3cf62ef46fcd95902410)) * set input type ‘email’ for email-based login ([#776](https://github.com/pocket-id/pocket-id/issues/776)) ([d541c9a](https://github.com/pocket-id/pocket-id/commit/d541c9ab4af8d7283891a80f886dd5d4ebc52f53)) ## v1.6.4 - 2025-07-21 [Section titled “v1.6.4 - 2025-07-21”](#v164---2025-07-21) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.6.4) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-41) * migration fails on postgres ([#762](https://github.com/pocket-id/pocket-id/issues/762)) ([35d5f88](https://github.com/pocket-id/pocket-id/commit/35d5f887ce7c88933d7e4c2f0acd2aeedd18c214)) ## v1.6.3 - 2025-07-21 [Section titled “v1.6.3 - 2025-07-21”](#v163---2025-07-21) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.6.3) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-42) * allow passkey names up to 50 characters ([b03e91b](https://github.com/pocket-id/pocket-id/commit/b03e91b6530c2393ad20ac49aa2cb2b4962651b2)) * ensure user inputs are normalized ([#724](https://github.com/pocket-id/pocket-id/issues/724)) ([7b4ccd1](https://github.com/pocket-id/pocket-id/commit/7b4ccd1f306f4882c52fe30133fcda114ef0d18b)) * show rename and delete buttons for passkeys without hovering over the row ([2952b15](https://github.com/pocket-id/pocket-id/commit/2952b1575542ecd0062fe740e2d6a3caad05190d)) * use object-contain for images on oidc-client list ([d3bc179](https://github.com/pocket-id/pocket-id/commit/d3bc1797b65ec8bc9201c55d06f3612093f3a873)) * use user-agent for identifying known device signins ([ef1d599](https://github.com/pocket-id/pocket-id/commit/ef1d5996624fc534190f80a26f2c48bbad206f49)) ## v1.6.2 - 2025-07-09 [Section titled “v1.6.2 - 2025-07-09”](#v162---2025-07-09) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.6.2) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-43) * ensure confirmation dialog shows on top of other components ([f103a54](https://github.com/pocket-id/pocket-id/commit/f103a547904070c5b192e519c8b5a8fed9d80e96)) * login failures on Postgres when IP is null ([#737](https://github.com/pocket-id/pocket-id/issues/737)) ([e1de593](https://github.com/pocket-id/pocket-id/commit/e1de593dcd30b7b04da3b003455134992b702595)) ## v1.6.1 - 2025-07-06 [Section titled “v1.6.1 - 2025-07-06”](#v161---2025-07-06) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.6.1) Note This release is the same as `v1.6.0` but the images are now tagged correctly. There was an issue that the `latest` tag was added to the distroless image instead of the regular one. ## v1.6.0 - 2025-07-06 [Section titled “v1.6.0 - 2025-07-06”](#v160---2025-07-06) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.6.0) ### Features [Section titled “Features”](#features-30) * add support for OAuth 2.0 Authorization Server Issuer Identification ([bf04256](https://github.com/pocket-id/pocket-id/commit/bf042563e997d57bb087705a5789fd72ffbed467)) * add distroless container additional variant + healthcheck command ([#716](https://github.com/pocket-id/pocket-id/issues/716)) * encrypt private keys saved on disk and in database ([#682](https://github.com/pocket-id/pocket-id/issues/682)) * enhance language selection message and add translation contribution link ([be52660](https://github.com/pocket-id/pocket-id/commit/be526602273c1689cb4057ca96d4214e7f817d1d)) * add “key-rotate” command ([#709](https://github.com/pocket-id/pocket-id/issues/709)) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-44) * allow profile picture update even if “allow own account edit” enabled ([9872608](https://github.com/pocket-id/pocket-id/commit/9872608d61a486f7b775f314d9392e0620bcd891)) * app config forms not updating with latest values ([#696](https://github.com/pocket-id/pocket-id/issues/696)) * auth fails when client IP is empty on Postgres ([#695](https://github.com/pocket-id/pocket-id/issues/695)) * custom claims input suggestions flickering ([49f1ab2](https://github.com/pocket-id/pocket-id/commit/49f1ab2f75df97d551fff5acbadcd55df74af617)) * keep sidebar in settings sticky ([e46f60a](https://github.com/pocket-id/pocket-id/commit/e46f60ac8d6944bcea54d0708af1950d98f66c3c)) * show friendly name in user group selection ([5c9e504](https://github.com/pocket-id/pocket-id/commit/5c9e504291b3bffe947bcbe907701806e301d1fe)) * support non UTF-8 LDAP IDs ([#714](https://github.com/pocket-id/pocket-id/issues/714)) * token introspection authentication not handled correctly ([#704](https://github.com/pocket-id/pocket-id/issues/704)) ## v1.5.0 - 2025-06-27 [Section titled “v1.5.0 - 2025-06-27”](#v150---2025-06-27) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.5.0) ### Features [Section titled “Features”](#features-31) * add self-service signup with token and open registration modes ([#672](https://github.com/pocket-id/pocket-id/issues/672)) * improve initial admin creation workflow ([287314f](https://github.com/pocket-id/pocket-id/commit/287314f01644e42ddb2ce1b1115bd14f2f0c1768)) * redact sensitive app config variables if set with env variable ([ba61cdb](https://github.com/pocket-id/pocket-id/commit/ba61cdba4eb3d5659f3ae6b6c21249985c0aa630)) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-45) * error page flickering after sign out ([1a77bd9](https://github.com/pocket-id/pocket-id/commit/1a77bd9914ea01e445ff3d6e116c9ed3bcfbf153)) * improve accent color picker disabled state ([d976bf5](https://github.com/pocket-id/pocket-id/commit/d976bf5965eda10e3ecb71821c23e93e5d712a02)) * less noisy logging for certain GET requests ([#681](https://github.com/pocket-id/pocket-id/issues/681) by @11notes) * margin of user sign up description ([052ac00](https://github.com/pocket-id/pocket-id/commit/052ac008c3a8c910d1ce79ee99b2b2f75e4090f4)) * remove duplicate request logging ([#678](https://github.com/pocket-id/pocket-id/issues/678) by @ryankask) * users can’t be updated by admin if self account editing is disabled ([29cb551](https://github.com/pocket-id/pocket-id/commit/29cb5513a03d1a9571969c8a42deec9b2bdee037)) ## v1.4.1 - 2025-06-22 [Section titled “v1.4.1 - 2025-06-22”](#v141---2025-06-22) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.4.1) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-46) * app not starting if UI config is disabled and Postgres is used ([7d36bda](https://github.com/pocket-id/pocket-id/commit/7d36bda769e25497dec6b76206a4f7e151b0bd72)) ## v1.4.0 - 2025-06-19 [Section titled “v1.4.0 - 2025-06-19”](#v140---2025-06-19) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.4.0) ### Features [Section titled “Features”](#features-32) * allow setting unix socket mode ([#661](https://github.com/pocket-id/pocket-id/issues/661) by @CnTeng) ([7677a3d](https://github.com/pocket-id/pocket-id/commit/7677a3de2c923c11a58bc8c4d1b2121d403a1504)) * auto-focus on the login buttons ([#647](https://github.com/pocket-id/pocket-id/issues/647) By @ItalyPaleAle) ([d679530](https://github.com/pocket-id/pocket-id/commit/d6795300b158b85dd9feadd561b6ecd891f5db0d)) * configurable local ipv6 ranges for audit log ([#657](https://github.com/pocket-id/pocket-id/issues/657)) ([d548523](https://github.com/pocket-id/pocket-id/commit/d5485238b8fd4cc566af00eae2b17d69a119f991)) * location filter for global audit log ([#662](https://github.com/pocket-id/pocket-id/issues/662)) ([ac5a121](https://github.com/pocket-id/pocket-id/commit/ac5a121f664b8127d0faf30c0f93432f30e7f33a)) * ui accent colors ([#643](https://github.com/pocket-id/pocket-id/issues/643)) ([883877a](https://github.com/pocket-id/pocket-id/commit/883877adec6fc3e65bd5a705499449959b894fb5)) * use icon instead of text on application image update hover state ([215531d](https://github.com/pocket-id/pocket-id/commit/215531d65c6683609b0b4a5505fdb72696fdb93e)) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-47) * allow images with uppercase file extension ([1bcb50e](https://github.com/pocket-id/pocket-id/commit/1bcb50edc335886dd722a4c69960c48cc3cd1687)) * center oidc client images if they are smaller than the box ([946c534](https://github.com/pocket-id/pocket-id/commit/946c534b0877a074a6b658060f9af27e4061397c)) * explicitly cache images to prevent unexpected behavior ([2e5d268](https://github.com/pocket-id/pocket-id/commit/2e5d2687982186c12e530492292d49895cb6043a)) * reduce duration of animations on login and signin page ([#648](https://github.com/pocket-id/pocket-id/issues/648) By @ItalyPaleAle) ([d770448](https://github.com/pocket-id/pocket-id/commit/d77044882d5a41da22df1c0099c1eb1f20bcbc5b)) ## v1.3.1 - 2025-06-09 [Section titled “v1.3.1 - 2025-06-09”](#v131---2025-06-09) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.3.1) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-48) * change timestamp of `client_credentials.sql` migration ([2935236](https://github.com/pocket-id/pocket-id/commit/2935236acee9c78c2fe6787ec8b5f53ae0eca047)) ## v1.3.0 - 2025-06-09 [Section titled “v1.3.0 - 2025-06-09”](#v130---2025-06-09) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.3.0) ### Features [Section titled “Features”](#features-33) * add API endpoint for user authorized clients ([d217083](https://github.com/pocket-id/pocket-id/commit/d217083059120171d5c555b09eefe6ba3c8a8d42)) * add unix socket support ([#615](https://github.com/pocket-id/pocket-id/issues/615) by @CnTeng) * JWT bearer assertions for client authentication ([#566](https://github.com/pocket-id/pocket-id/issues/566) by @ItalyPaleAle) * new color theme for the UI ([97f7326](https://github.com/pocket-id/pocket-id/commit/97f7326da40265a954340d519661969530f097a0)) * oidc client data preview ([#624](https://github.com/pocket-id/pocket-id/issues/624)) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-49) * don’t load app config and user on every route change ([bdcef60](https://github.com/pocket-id/pocket-id/commit/bdcef60cab6a61e1717661e918c42e3650d23fee)) * misleading text for disable animations option ([657a51f](https://github.com/pocket-id/pocket-id/commit/657a51f7ed8a77e8a937971032091058aacfded6)) * OIDC client image can’t be deleted ([61b62d4](https://github.com/pocket-id/pocket-id/commit/61b62d461200c1359a16c92c9c62530362a4785c)) * UI config overridden by env variables don’t apply on first start ([5e9096e](https://github.com/pocket-id/pocket-id/commit/5e9096e328741ba2a0e03835927fe62e6aea2a89)) ## v1.2.0 - 2025-06-03 [Section titled “v1.2.0 - 2025-06-03”](#v120---2025-06-03) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.2.0) ### Features [Section titled “Features”](#features-34) * auto detect callback url ([#583](https://github.com/pocket-id/pocket-id/issues/583)) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-50) * allow users to update their locale even when own account update disabled ([6c00aaa](https://github.com/pocket-id/pocket-id/commit/6c00aaa3efa75c76d340718698a0f4556e8de268)) * clear default app config variables from database ([decf8ec](https://github.com/pocket-id/pocket-id/commit/decf8ec70b5f6a69fe201d6e4ad60ee62e374ad0)) * fallback to primary language if no translation available for specific country ([2440379](https://github.com/pocket-id/pocket-id/commit/2440379cd11b4a6da7c52b122ba8f49d7c72ce1d)) * improve spacing on auth screens ([04fcf11](https://github.com/pocket-id/pocket-id/commit/04fcf1110e97b42dc5f0c20e169c569075d1e797)) * page scrolls up on form submission ([31ad904](https://github.com/pocket-id/pocket-id/commit/31ad904367e53dd47a15abcce5402dfe84828a14)) * run jobs at interval instead of specific time ([#585](https://github.com/pocket-id/pocket-id/issues/585) by @ItalyPaleAle) * show LAN for auditlog location for internal networks ([b874681](https://github.com/pocket-id/pocket-id/commit/b8746818240fde052e6f3b5db5c3355d7bbfcbda)) * small fixes in analytics_job ([#582](https://github.com/pocket-id/pocket-id/issues/582) by @ItalyPaleAle) * whitelist authorization header for CORS ([b9489b5](https://github.com/pocket-id/pocket-id/commit/b9489b5e9a32a2a3f54d48705e731a7bcf188d20)) ## v1.1.0 - 2025-05-28 [Section titled “v1.1.0 - 2025-05-28”](#v110---2025-05-28) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.1.0) Note This version introduces a heartbeat request that gets sent once everyday to the [Pocket ID analytics server](https://github.com/pocket-id/analytics) to count how many instances of Pocket ID exist. The heartbeat request only contains a random instance ID, the version of Pocket ID and when it was first/last seen. Seeing how many active Pocket ID instances are out there genuinely motivates us to keep developing and maintaining the project. Of course this heartbeat can also be disabled by setting `ANALYTICS_DISABLED` to `true`. For more information visit the [docs page](https://pocket-id.org/docs/configuration/analytics). ### Features [Section titled “Features”](#features-35) * add daily heartbeat request for counting Pocket ID instances ([#578](https://github.com/pocket-id/pocket-id/issues/578)) * require user verification for passkey sign in ([68e4b67](https://github.com/pocket-id/pocket-id/commit/68e4b67bd212e31ecc20277bfd293c94bf7f3642)) * show allowed group count on oidc client list ([#567](https://github.com/pocket-id/pocket-id/issues/567)) ([38d7ee4](https://github.com/pocket-id/pocket-id/commit/38d7ee4432e0dacc2cfbabad4bfd9336b8b84079)) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-51) * use ldapAttributeUserUsername for finding group members ([#565](https://github.com/pocket-id/pocket-id/issues/565)) ## v1.0.0 - 2025-05-24 [Section titled “v1.0.0 - 2025-05-24”](#v100---2025-05-24) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v1.0.0) Caution This release contains breaking changes and Pocket ID won’t work correctly if you don’t follow the migration steps.  → Please follow the [migration guide](https://pocket-id.org/docs/setup/migrate-to-v1/). ### Features [Section titled “Features”](#features-36) * serve the static frontend trough the backend (#520) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-52) * animation speed set to max of 300ms ([c726c16](https://github.com/pocket-id/pocket-id/commit/c726c1621b8bd88b20cb05263f6d10888f0af8e2)) * custom logo not correctly loaded if UI configuration is disabled ([bf710ae](https://github.com/pocket-id/pocket-id/commit/bf710aec5625c9dcb43c83d920318a036a135bae)) * show correct app name on sign out page ([131f470](https://github.com/pocket-id/pocket-id/commit/131f470757044fddd0989a76e9dc9e310f19819c)) * trim whitespaces from string inputs ([059073d](https://github.com/pocket-id/pocket-id/commit/059073d4c24e34c142dddd4c150c384779fb51a9)) ## v0.53.0 - 2025-05-08 [Section titled “v0.53.0 - 2025-05-08”](#v0530---2025-05-08) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v0.53.0) ### Features [Section titled “Features”](#features-37) * add support for `TZ` environment variable ([5e2e947](https://github.com/pocket-id/pocket-id/commit/5e2e947fe09fa881a7bbc70133a243a4baf30e90)) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-53) * handle CORS correctly for endpoints that SPAs need ([#513](https://github.com/pocket-id/pocket-id/issues/513)) ## v0.52.0 - 2025-05-06 [Section titled “v0.52.0 - 2025-05-06”](#v0520---2025-05-06) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v0.52.0) ### Features [Section titled “Features”](#features-38) * add healthz endpoint ([#494](https://github.com/pocket-id/pocket-id/issues/494) by @ItalyPaleAle) * add OpenTelemetry tracing and metrics ([#495](https://github.com/pocket-id/pocket-id/issues/495) by @daenney) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-54) * correctly set script permissions inside Docker container ([c55fef0](https://github.com/pocket-id/pocket-id/commit/c55fef057cdcec867af91b29968541983cd80ec0)) ## v0.51.1 - 2025-05-03 [Section titled “v0.51.1 - 2025-05-03”](#v0511---2025-05-03) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v0.51.1) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-55) * allow LDAP users to update their locale ([0b9cbf4](https://github.com/pocket-id/pocket-id/commit/0b9cbf47e36a332cfd854aa92e761264fb3e4795)) * last name still showing as required on account form ([#492](https://github.com/pocket-id/pocket-id/issues/492)) * non admin users weren’t able to call the end session endpoint ([6bd6cef](https://github.com/pocket-id/pocket-id/commit/6bd6cefaa6dc571a319a6a1c2b2facc2404eadd3)) ## v0.51.0 - 2025-04-28 [Section titled “v0.51.0 - 2025-04-28”](#v0510---2025-04-28) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v0.51.0) ### Features [Section titled “Features”](#features-39) * new login code card position for mobile devices ([#452](https://github.com/pocket-id/pocket-id/issues/452) by @James18232) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-56) * do not require PKCE for public clients ([ce24372](https://github.com/pocket-id/pocket-id/commit/ce24372c571cc3b277095dc6a4107663d64f45b3)) * hide global audit log switch for non admin users ([1efd1d1](https://github.com/pocket-id/pocket-id/commit/1efd1d182dbb6190d3c7e27034426c9e48781b4a)) * return correct error message if user isn’t authorized ([86d2b5f](https://github.com/pocket-id/pocket-id/commit/86d2b5f59f26cb944017826cbd8df915cdc986f1)) * updating scopes of an authorized client fails with Postgres ([0a24ab8](https://github.com/pocket-id/pocket-id/commit/0a24ab80010eb5a15d99915802c6698274a5c57c)) ## v0.50.0 - 2025-04-27 [Section titled “v0.50.0 - 2025-04-27”](#v0500---2025-04-27) [Release](https://github.com/pocket-id/pocket-id/releases/tag/v0.50.0) ### Features [Section titled “Features”](#features-40) * device authorization endpoint ([#270](https://github.com/pocket-id/pocket-id/issues/270)) * make family name optional ([#476](https://github.com/pocket-id/pocket-id/issues/476)) ### Bug Fixes [Section titled “Bug Fixes”](#bug-fixes-57) * incorrectly swapped refreshToken and accessToken (#490 by @j-baker) * do not override XDG_DATA_HOME/XDG_CONFIG_HOME if they are already set ([#472](https://github.com/pocket-id/pocket-id/issues/472) by @it) * pass context to methods that were missing it ([#487](https://github.com/pocket-id/pocket-id/issues/487) by @ItalyPaleAle) * prevent deadlock when trying to delete LDAP users ([#471](https://github.com/pocket-id/pocket-id/issues/471) by @ItalyPaleAle) * rootless Caddy data and configuration ([#470](https://github.com/pocket-id/pocket-id/issues/470) by @eiqnepm)