Support multiple OIDC providers
kaya-oidc 0.0.6 can run several providers in one app (OIDCProviders), each with its own login route and namespaced session state. Adopt it: providers are configured in indexed, contiguous OIDC_<n>_* blocks (0-based) with OIDC_<n>_PROVIDER naming the provider in its login URL and session keys. The old unindexed OIDC_ISSUER/OIDC_CLIENT_ID/... names are no longer read; startup fails with a rename hint when they are set. With no OIDC variables at all, the single dev mock provider named "default" is used, as before. The platform now authenticates through OIDCProviders: auth.current_user returns the session's user (sessions stay single-identity, so at most one provider is logged in) and require_auth/route handlers use it, while the websocket path keeps scanning for any provider's user. New routes expose the configuration to the SPA and keep old links working: GET /api/auth/providers lists the login URLs, GET /auth/login redirects to the first provider and GET /auth/logout to whichever provider the session is logged in with. The lobby renders one login button per provider from that endpoint. Update the env examples, compose and k8s manifests to the indexed scheme, document the multiple-provider setup and the migration, and cover it with config, auth and route tests.
This commit is contained in:
+47
-5
@@ -43,7 +43,8 @@ Because the browser and the app both talk to the OIDC issuer at
|
||||
echo "127.0.0.1 mockoauth" | sudo tee -a /etc/hosts
|
||||
```
|
||||
|
||||
Then log in: `GET http://localhost:8080/auth/login`, type any username
|
||||
Then log in: `GET http://localhost:8080/auth/login` (a provider-agnostic
|
||||
alias that redirects to the first configured provider), type any username
|
||||
(e.g. `alice`) in the interactive login, and you are redirected back with a
|
||||
session cookie. That cookie authenticates both the REST API and the
|
||||
WebSocket endpoint.
|
||||
@@ -65,10 +66,13 @@ All configuration comes from environment variables (see `.env.example`):
|
||||
| `DATABASE_OPTIONS` | unset | Extra DSN query parameters, e.g. `ssl=require` |
|
||||
| `DATABASE_URL` | unset | Full-DSN override; when set, the `DATABASE_*` parts above are ignored (used for sqlite in tests and for managed-DB URLs) |
|
||||
| `REDIS_URL` | unset | Redis DSN for sessions + live games. Unset falls back to in-memory stores |
|
||||
| `OIDC_ISSUER` | `http://localhost:8180/tavolo` | OIDC issuer URL |
|
||||
| `OIDC_CLIENT_ID` | `tavolo` | OIDC client id |
|
||||
| `OIDC_CLIENT_SECRET` | unset | OIDC client secret |
|
||||
| `OIDC_REDIRECT_URI` | `http://localhost:8080/auth/callback` | Login callback URL |
|
||||
| `OIDC_<n>_PROVIDER` | `default` ¹ | Provider name (required when OIDC is configured): used in the login URL `/auth/<provider>/login` and to namespace its session keys. Unique, `[A-Za-z0-9_-]+` |
|
||||
| `OIDC_<n>_ISSUER` | `http://localhost:8180/tavolo` ¹ | OIDC issuer URL |
|
||||
| `OIDC_<n>_CLIENT_ID` | `tavolo` ¹ | OIDC client id |
|
||||
| `OIDC_<n>_CLIENT_SECRET` | unset | OIDC client secret; leave unset for public clients |
|
||||
| `OIDC_<n>_REDIRECT_URI` | `http://localhost:8080/auth/<provider>/callback` | Login callback URL; must be registered at the provider |
|
||||
| `OIDC_<n>_POST_LOGIN_REDIRECT` | `/` | Where the browser is sent after login |
|
||||
| `OIDC_<n>_POST_LOGOUT_REDIRECT` | `/` | Where the browser is sent after logout |
|
||||
| `GAME_TTL_SECONDS` | `86400` | Sliding TTL of a live game in Redis |
|
||||
| `HAND_ACK_TIMEOUT_SECONDS` | `30` | Seconds the scopone between-hands scoring summary waits for acknowledgements (wired into the `ScoponeEngine`) |
|
||||
| `TURN_TIMEOUT_SECONDS` | `30` | Seconds a scopone player has to play before the server plays a random legal card for them (wired into the `ScoponeEngine`) |
|
||||
@@ -90,6 +94,44 @@ All configuration comes from environment variables (see `.env.example`):
|
||||
| `OTEL_METRICS_POLL_INTERVAL_SECONDS` | `15` | How often the session/game count gauges are refreshed |
|
||||
| `APP_HOST` / `APP_PORT` | `0.0.0.0` / `8080` | Bind address |
|
||||
|
||||
¹ When no `OIDC_<n>_*` variable is set at all, a single provider named
|
||||
`default` pointing at the dev mock IdP is used. Indices must be contiguous
|
||||
from 0 (`OIDC_0_*`, `OIDC_1_*`, ...).
|
||||
|
||||
### Multiple OIDC providers
|
||||
|
||||
Providers are configured in indexed blocks; each becomes its own login
|
||||
route `/auth/<provider>/login` with its own callback URL and session
|
||||
namespace:
|
||||
|
||||
```sh
|
||||
OIDC_0_PROVIDER=google
|
||||
OIDC_0_ISSUER=https://accounts.google.com
|
||||
OIDC_0_CLIENT_ID=...
|
||||
OIDC_0_CLIENT_SECRET=...
|
||||
OIDC_0_REDIRECT_URI=https://tavolo.example.com/auth/google/callback
|
||||
|
||||
OIDC_1_PROVIDER=github
|
||||
OIDC_1_ISSUER=https://github.com/login/oauth
|
||||
OIDC_1_CLIENT_ID=...
|
||||
OIDC_1_CLIENT_SECRET=...
|
||||
OIDC_1_REDIRECT_URI=https://tavolo.example.com/auth/github/callback
|
||||
```
|
||||
|
||||
The login page reads `GET /api/auth/providers` and shows one button per
|
||||
provider. `GET /auth/login` redirects to the first provider (useful for
|
||||
bookmarks and scripts), and `GET /auth/logout` signs out whichever
|
||||
provider the session is logged in with.
|
||||
|
||||
Sessions hold a single identity: logging in with another provider
|
||||
replaces the previous one. Each provider's `sub` is a separate account,
|
||||
so match history and Elo ratings are per provider identity (someone using
|
||||
two providers has two accounts). Migrating from the pre-0.0.6 unindexed
|
||||
variables: rename `OIDC_ISSUER`/`OIDC_CLIENT_ID`/... to `OIDC_0_...`, add
|
||||
`OIDC_0_PROVIDER`, and register the new callback path
|
||||
(`/auth/<provider>/callback`) at the provider. Sessions survive only when
|
||||
the provider is named `default`; otherwise users log in once more.
|
||||
|
||||
## Logging
|
||||
|
||||
The application logs through the Python stdlib `logging` module, one
|
||||
|
||||
Reference in New Issue
Block a user