feat: OIDC provider for "Login with Pangolin" #180

Open
opened 2026-04-05 17:02:01 +02:00 by MrUnknownDE · 0 comments
Owner

Originally created by @mallendeo on 3/1/2026

Community Contribution License Agreement

By creating this pull request, I grant the project maintainers an unlimited,
perpetual license to use, modify, and redistribute these contributions under any terms they
choose, including both the AGPLv3 and the Fossorial Commercial license terms. I
represent that I have the right to grant this license for all contributed content.

Description

Implements Pangolin as an OIDC provider for “Login with Pangolin”, with full OAuth client management for admins and app-consent management for users.

See https://github.com/orgs/fosrl/discussions/21

Scaffolding and ongoing development were AI-assisted (Opus 4.6 / Codex 5.3); not all code has been manually reviewed. Contributions welcome.

What’s included

  • OAuth 2.0 Authorization Code flow with PKCE
  • OIDC endpoints: discovery, authorize, token, userinfo, JWKS, revoke
  • OIDC logout support:
    • RP-initiated logout (end_session_endpoint)
    • back-channel logout dispatch
  • Admin OAuth Clients UI: create, edit, delete, rotate secret, advanced settings
  • User "Connected Apps" page to revoke grants
  • Edit profile dialog (name, username) to support profile claims
  • Claims updates, including given_name, family_name, and org-scoped groups
  • i18n strings (English only, AI translation removed / out of scope)
  • SQLite + PostgreSQL schema/migration updates for v1.17.0

How to test

If upgrading from a previous install, route /.well-known to the API service.

In config/traefik/dynamic_config.yml, update the Next.js and API router rules:

next-router:
  rule: "Host(`yourdomain.com`) && !PathPrefix(`/api/v1`) && !PathPrefix(`/.well-known`)"
  # ...

api-router:
  rule: "Host(`yourdomain.com`) && (PathPrefix(`/api/v1`) || PathPrefix(`/.well-known`))"
  # ...

Restart Traefik after changing this.

Create an OAuth client

  1. Go to Org Settings > OAuth Clients
  2. Click Create Client
  3. Fill in name, redirect URI, and scopes
  4. Save the client ID and secret shown in the dialog

Verify discovery

curl https://yourdomain.com/.well-known/openid-configuration

Expected: JSON with fields like issuer, authorization_endpoint,
token_endpoint, userinfo_endpoint, jwks_uri, revocation_endpoint,
and end_session_endpoint.

Available scopes and claims

Scope Claims
openid sub
profile name, preferred_username, given_name, family_name
email email, email_verified
groups groups (organization/role memberships, formatted like :)

Endpoints

Endpoint Path
Discovery /.well-known/openid-configuration
Authorization /oauth/authorize (browser redirect)
Token /api/v1/oauth/token
Userinfo /api/v1/oauth/userinfo
JWKS /api/v1/oauth/jwks
Revoke /api/v1/oauth/revoke
Logout /api/v1/oauth/logout

Demo

TODO

*Originally created by @mallendeo on 3/1/2026* ## Community Contribution License Agreement By creating this pull request, I grant the project maintainers an unlimited, perpetual license to use, modify, and redistribute these contributions under any terms they choose, including both the AGPLv3 and the Fossorial Commercial license terms. I represent that I have the right to grant this license for all contributed content. ## Description Implements Pangolin as an OIDC provider for “Login with Pangolin”, with full OAuth client management for admins and app-consent management for users. See https://github.com/orgs/fosrl/discussions/21 Scaffolding and ongoing development were AI-assisted (Opus 4.6 / Codex 5.3); not all code has been manually reviewed. Contributions welcome. ## What’s included - OAuth 2.0 Authorization Code flow with PKCE - OIDC endpoints: discovery, authorize, token, userinfo, JWKS, revoke - OIDC logout support: - RP-initiated logout (`end_session_endpoint`) - back-channel logout dispatch - Admin OAuth Clients UI: create, edit, delete, rotate secret, advanced settings - User "Connected Apps" page to revoke grants - Edit profile dialog (name, username) to support profile claims - Claims updates, including `given_name`, `family_name`, and org-scoped `groups` - i18n strings (English only, AI translation removed / out of scope) - SQLite + PostgreSQL schema/migration updates for v1.17.0 ## How to test If upgrading from a previous install, route `/.well-known` to the API service. In `config/traefik/dynamic_config.yml`, update the Next.js and API router rules: ```yaml next-router: rule: "Host(`yourdomain.com`) && !PathPrefix(`/api/v1`) && !PathPrefix(`/.well-known`)" # ... api-router: rule: "Host(`yourdomain.com`) && (PathPrefix(`/api/v1`) || PathPrefix(`/.well-known`))" # ... ``` Restart Traefik after changing this. ### Create an OAuth client 1. Go to Org Settings > OAuth Clients 2. Click Create Client 3. Fill in name, redirect URI, and scopes 4. Save the client ID and secret shown in the dialog ### Verify discovery curl https://yourdomain.com/.well-known/openid-configuration Expected: JSON with fields like `issuer`, `authorization_endpoint`, `token_endpoint`, `userinfo_endpoint`, `jwks_uri`, `revocation_endpoint`, and `end_session_endpoint`. ### Available scopes and claims | Scope | Claims | | ------- | --------------------------------------------------------------------------- | | openid | sub | | profile | name, preferred_username, given_name, family_name | | email | email, email_verified | | groups | groups (organization/role memberships, formatted like <orgName>:<roleName>) | ### Endpoints | Endpoint | Path | | ------------- | ----------------------------------- | | Discovery | /.well-known/openid-configuration | | Authorization | /oauth/authorize (browser redirect) | | Token | /api/v1/oauth/token | | Userinfo | /api/v1/oauth/userinfo | | JWKS | /api/v1/oauth/jwks | | Revoke | /api/v1/oauth/revoke | | Logout | /api/v1/oauth/logout | ## Demo TODO
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github/pangolin#180