feat: sync HTTP callback OIDC setup
This commit is contained in:
parent
bf72c246b6
commit
f53579416e
26 changed files with 557 additions and 133 deletions
|
|
@ -51,7 +51,7 @@ This document describes every setting loaded by `internal/config`. Defaults and
|
|||
| Setting | Type / code default | Description and constraints |
|
||||
|---|---|---|
|
||||
| `TELESRV_DEBUG_ADDR` | nullable address / `127.0.0.1:6060` | pprof/debug listener. Empty disables it. Keep loopback-only; use an SSH tunnel for production profiling. |
|
||||
| `TELESRV_BOT_API_ADDR` | nullable address / empty | Minimal HTTP Bot API listener. Empty disables it. It shares MTProto app/store facts. |
|
||||
| `TELESRV_BOT_API_ADDR` | nullable address / empty | Minimal HTTP Bot API listener. Empty disables it. It shares MTProto app/store facts. `setWebhook` accepts any valid `http://` or `https://` host/IP and port in `1..65535`. |
|
||||
| `TELESRV_ADMIN_API_ADDR` | nullable address / empty | In-process Admin write API listener. Empty disables it; production should bind loopback. |
|
||||
| `TELESRV_ADMIN_API_TOKEN` | secret string / empty | Admin API bearer token. Required when the Admin API is enabled and must match the Admin UI token configuration. |
|
||||
| `TELESRV_ADMIN_UI_ADDR` | address / `127.0.0.1:2600` | Standalone `cmd/telesrv-admin` listen address. |
|
||||
|
|
@ -62,7 +62,189 @@ This document describes every setting loaded by `internal/config`. Defaults and
|
|||
| `TELESRV_PUBLIC_APP_SCHEME` | URL scheme / `telesrv` | Automatic app-open scheme on landing pages. Must match patched client registration. `tg`, `http`, and `https` are rejected. |
|
||||
| `TELESRV_PUBLIC_WEB_BASE_URL` | HTTP(S) URL / `https://web.telesrv.net` | Web-client root used by public username pages. Same URL validation as `TELESRV_PUBLIC_BASE_URL`. |
|
||||
| `TELESRV_PUBLIC_APP_NAME` | string / `telesrv` | Public landing-page product name; trimmed, non-empty, no control characters, maximum 64 Unicode characters. |
|
||||
| `TELESRV_PUBLIC_LINK_WEB_ADDR` | nullable address / empty | Read-only username/avatar/sticker/emoji/chatlist landing-page listener. Empty disables it. Production should bind loopback behind exact nginx routes. `.env.example` enables `127.0.0.1:2401` for development. |
|
||||
| `TELESRV_PUBLIC_LINK_WEB_ADDR` | nullable address / empty | Read-only username/avatar/sticker/emoji/chatlist/collectible-gift landing-page listener. Empty disables it. Production should bind loopback behind exact nginx routes. `.env.example` enables `127.0.0.1:2401` for development. |
|
||||
| `TELESRV_TELEGRAM_LOGIN_ENABLE` | bool / `false` | Mount the self-hosted Telegram Login/OIDC provider on `TELESRV_PUBLIC_LINK_WEB_ADDR`. Enabling it requires that listener and all key files below. |
|
||||
| `TELESRV_TELEGRAM_LOGIN_ISSUER` | absolute origin URL / `TELESRV_PUBLIC_BASE_URL` | Exact public issuer used in discovery and tokens. HTTPS is required by default; paths, credentials, query, and fragment are rejected. The next setting permits any HTTP host/IP. |
|
||||
| `TELESRV_TELEGRAM_LOGIN_ALLOW_HTTP` | bool / `false` | When enabled, permits any valid HTTP issuer, BotFather Web origin, redirect URI, and native HTTP callback, without loopback, subnet, or port restrictions. When disabled, those Web URLs still require HTTPS. |
|
||||
| `TELESRV_TELEGRAM_LOGIN_SIGNING_KEYS_FILE` | path / `data/telegram-login/signing-keys.json` | JOSE private-key ring generated by `cmd/telegramloginkeygen`; active plus retiring public keys are published through JWKS. |
|
||||
| `TELESRV_TELEGRAM_LOGIN_CODE_KEYS_FILE` | path / `data/telegram-login/code-keys.json` | AES-256-GCM envelope-key ring for recoverable, one-time authorization codes. |
|
||||
| `TELESRV_TELEGRAM_LOGIN_SECRET_PEPPER_FILE` | path / `data/telegram-login/client-secret-pepper` | Deployment pepper for HMAC-SHA-256 client-secret hashes. The file must contain a base64 encoding of exactly 32 random bytes. |
|
||||
| `TELESRV_TELEGRAM_LOGIN_REQUEST_TTL` | duration / `5m` | Pending authorization lifetime; bounded to `1m..15m`. |
|
||||
| `TELESRV_TELEGRAM_LOGIN_CODE_TTL` | duration / `2m` | One-time code lifetime; bounded to `30s..10m`. |
|
||||
| `TELESRV_TELEGRAM_LOGIN_ID_TOKEN_TTL` | duration / `1h` | Signed ID-token lifetime; bounded to `1m..24h`. Retiring signing keys must cover this window. |
|
||||
| `TELESRV_TELEGRAM_LOGIN_TRUSTED_PROXY_CIDRS` | comma-separated CIDRs / empty | Only requests whose direct peer is in this list may supply `Forwarded`/`X-Forwarded-*` client metadata. The documented nginx deployment uses `127.0.0.1/32,::1/128`. |
|
||||
| `TELESRV_TELEGRAM_LOGIN_RETENTION` | duration / `168h` | Retention after terminal request/code/revocation state; bounded to `1h..90d`. |
|
||||
| `TELESRV_TELEGRAM_LOGIN_SWEEP_INTERVAL` | duration / `5m` | Retention worker interval; bounded to `10s..1h`. |
|
||||
| `TELESRV_TELEGRAM_LOGIN_SWEEP_BATCH` | int / `500` | Maximum rows per retention pass; bounded to `1..1000`. |
|
||||
|
||||
### 3.1 Complete Telegram Login / OIDC setup
|
||||
|
||||
#### 1. Generate `data/telegram-login` once
|
||||
|
||||
Run this from the `telesrv` repository root:
|
||||
|
||||
```powershell
|
||||
go run ./cmd/telegramloginkeygen -mode init -dir data/telegram-login
|
||||
Get-ChildItem .\data\telegram-login
|
||||
```
|
||||
|
||||
The same command works on Linux; restrict the generated directory afterward:
|
||||
|
||||
```bash
|
||||
go run ./cmd/telegramloginkeygen -mode init -dir data/telegram-login
|
||||
chmod 0700 data/telegram-login
|
||||
chmod 0600 data/telegram-login/*
|
||||
```
|
||||
|
||||
Initialization creates the following private files. It never prints key material and refuses to
|
||||
overwrite an existing `signing-keys.json`, `code-keys.json`, or `client-secret-pepper`:
|
||||
|
||||
- `signing-keys.json` plus three `signing-*.pem` files: the manifest and private keys for RS256,
|
||||
ES256, and EdDSA ID-token signatures;
|
||||
- `code-keys.json`: the AES-256-GCM envelope-key ring for one-time authorization codes;
|
||||
- `client-secret-pepper`: a 32-byte deployment pepper used to store and verify OIDC Client Secret
|
||||
digests.
|
||||
|
||||
The repository ignores `data/*` by default. Never put this directory in Git, release archives,
|
||||
logs, or ordinary backups. All instances must mount the same protected files and restart together
|
||||
after rotation. Losing the pepper invalidates existing Client Secret verification. Losing a signing
|
||||
key that is still in its publication window invalidates otherwise-live ID tokens against JWKS.
|
||||
|
||||
#### 2. Configure and start the Provider
|
||||
|
||||
This example exposes OIDC directly at `http://192.0.2.25:2401`; replace it with the server address
|
||||
that clients can actually reach. Bind `0.0.0.0:2401` for direct LAN/public access, or keep
|
||||
`127.0.0.1:2401` when an on-host reverse proxy is the only caller:
|
||||
|
||||
```env
|
||||
TELESRV_PUBLIC_BASE_URL=http://192.0.2.25:2401
|
||||
TELESRV_PUBLIC_LINK_WEB_ADDR=0.0.0.0:2401
|
||||
TELESRV_PUBLIC_APP_SCHEME=telesrv
|
||||
|
||||
TELESRV_TELEGRAM_LOGIN_ENABLE=true
|
||||
TELESRV_TELEGRAM_LOGIN_ISSUER=http://192.0.2.25:2401
|
||||
TELESRV_TELEGRAM_LOGIN_ALLOW_HTTP=true
|
||||
TELESRV_TELEGRAM_LOGIN_SIGNING_KEYS_FILE=data/telegram-login/signing-keys.json
|
||||
TELESRV_TELEGRAM_LOGIN_CODE_KEYS_FILE=data/telegram-login/code-keys.json
|
||||
TELESRV_TELEGRAM_LOGIN_SECRET_PEPPER_FILE=data/telegram-login/client-secret-pepper
|
||||
```
|
||||
|
||||
For HTTPS, set the issuer and public base to the exact HTTPS origin and leave
|
||||
`TELESRV_TELEGRAM_LOGIN_ALLOW_HTTP=false`. The issuer becomes the token `iss` and the root of all
|
||||
discovery endpoints, so its scheme, host, and port must exactly match the address used by relying
|
||||
parties. Start or restart `telesrv`, then verify the public endpoints:
|
||||
|
||||
```powershell
|
||||
curl.exe http://192.0.2.25:2401/.well-known/openid-configuration
|
||||
curl.exe http://192.0.2.25:2401/.well-known/jwks.json
|
||||
curl.exe -I http://192.0.2.25:2401/js/telegram-login.js
|
||||
```
|
||||
|
||||
The discovery `issuer` must equal the configured value, and its `authorization_endpoint`,
|
||||
`token_endpoint`, and `jwks_uri` must be reachable by the relying party. A reverse proxy must pass
|
||||
through `/.well-known/openid-configuration`, `/.well-known/jwks.json`, `/auth`, `/auth/status`,
|
||||
`/token`, `/crossapp`, `/inapp`, `/telegram-login.js`, and `/js/telegram-login.js` unchanged.
|
||||
|
||||
#### 3. Create an OIDC Client with the local `@BotFather`
|
||||
|
||||
Create a bot with `/newbot` or select an existing bot. In the local `@BotFather`, run `/setlogin`
|
||||
and choose that bot. Initial setup returns:
|
||||
|
||||
- `Client ID`: the bot user ID as a decimal string;
|
||||
- `Client Secret`: shown once, separate from the Bot API token, and meant to be saved immediately
|
||||
in a secret manager.
|
||||
|
||||
Send each configuration command separately. This example runs the relying party at
|
||||
`http://192.0.2.30:3000`:
|
||||
|
||||
```text
|
||||
add origin http://192.0.2.30:3000
|
||||
add redirect http://192.0.2.30:3000/oauth/callback
|
||||
algorithm RS256
|
||||
enable
|
||||
```
|
||||
|
||||
An `origin` is an exact Web origin without a path, query, or fragment; it authorizes the JS SDK,
|
||||
popup CORS, and legacy `login_url`. A `redirect` is the exact full URI that receives an
|
||||
Authorization Code. Wildcards and prefix matching are not supported. Use `/logininfo` to inspect
|
||||
status and registrations; use `/setlogin` to add/remove URLs, change the algorithm, or disable the
|
||||
client; use `/resetloginsecret` to rotate the Client Secret. Available algorithms are RS256,
|
||||
ES256, EdDSA, and ES256K only when its build/key ring is present. EdDSA and ES256K accept only the
|
||||
`openid` scope.
|
||||
|
||||
#### 4. Integrate a relying party with standard OIDC
|
||||
|
||||
Start by loading:
|
||||
|
||||
```text
|
||||
http://192.0.2.25:2401/.well-known/openid-configuration
|
||||
```
|
||||
|
||||
The standard flow is Authorization Code with PKCE S256:
|
||||
|
||||
1. Generate random `state`, `nonce`, and PKCE `code_verifier`; derive the S256 `code_challenge`.
|
||||
2. Open the discovery `authorization_endpoint` with `client_id`, the exact `redirect_uri`,
|
||||
`response_type=code`, a `scope` containing `openid`, `state`, `nonce`, `code_challenge`, and
|
||||
`code_challenge_method=S256`.
|
||||
3. After the user approves in TDesktop/Android, verify `state` at the relying-party callback and
|
||||
read the one-time code.
|
||||
4. Server-side, POST `grant_type=authorization_code`, the code, the same `redirect_uri`, and
|
||||
`code_verifier` to the discovery `token_endpoint`. Confidential clients authenticate with HTTP
|
||||
Basic or `client_secret_post`.
|
||||
5. Verify the ID-token signature with the discovery `jwks_uri`, then strictly validate `iss`,
|
||||
`aud`, `exp`, `nonce`, and a non-empty `sub`. Decoding without signature verification is not
|
||||
sufficient.
|
||||
|
||||
Supported scopes are `openid`, `profile`, `phone`, and `telegram:bot_access`. The provider does not
|
||||
currently expose UserInfo, refresh tokens, or an introspection endpoint. Browser applications may
|
||||
load `<issuer>/js/telegram-login.js` for the local JS SDK. A Client Secret must remain server-side.
|
||||
|
||||
#### 5. Verify the complete path with the Bedolaga demo
|
||||
|
||||
Install the demo dependencies:
|
||||
|
||||
```powershell
|
||||
python -m venv "$env:TEMP\telesrv-bedolaga-demo-venv"
|
||||
& "$env:TEMP\telesrv-bedolaga-demo-venv\Scripts\python.exe" -m pip install `
|
||||
-r .\cmd\bots\bedolagaformat\requirements.txt
|
||||
```
|
||||
|
||||
Put the Client ID/Secret from step 3 and the same bot's Bot API token only in process environment:
|
||||
|
||||
```powershell
|
||||
$env:TELESRV_BOT_TOKEN = "<bot_id>:<bot_api_secret>"
|
||||
$env:TELESRV_BOT_API_SERVER = "http://192.0.2.25:8081"
|
||||
$env:TELESRV_BOT_LOGIN_DEMO = "1"
|
||||
$env:TELESRV_BOT_LOGIN_ISSUER = "http://192.0.2.25:2401"
|
||||
$env:TELESRV_BOT_LOGIN_CLIENT_ID = "<Client ID returned by BotFather>"
|
||||
$env:TELESRV_BOT_LOGIN_CLIENT_SECRET = "<one-time OIDC Client Secret>"
|
||||
$env:TELESRV_BOT_LOGIN_PUBLIC_URL = "http://192.0.2.30:3000"
|
||||
$env:TELESRV_BOT_LOGIN_LISTEN = "0.0.0.0:3000"
|
||||
|
||||
& "$env:TEMP\telesrv-bedolaga-demo-venv\Scripts\python.exe" `
|
||||
.\cmd\bots\bedolagaformat\demo.py --drop-pending --login-demo
|
||||
```
|
||||
|
||||
The BotFather origin must equal `TELESRV_BOT_LOGIN_PUBLIC_URL`, and the redirect must equal
|
||||
`<TELESRV_BOT_LOGIN_PUBLIC_URL>/oauth/callback`. Send `/logindemo` to the bot. The first button
|
||||
tests Bot API `login_url` plus the HMAC callback; the second page tests the local JS SDK popup and
|
||||
Authorization Code + PKCE/JWKS. Omitting the Client Secret leaves JS popup verification available
|
||||
but explicitly disables the server-side code flow.
|
||||
|
||||
#### 6. Rotate keys
|
||||
|
||||
When rotating a signing key, retain the old public key for at least the configured ID-token TTL
|
||||
plus ten minutes. Restart all instances together after the operation:
|
||||
|
||||
```powershell
|
||||
go run ./cmd/telegramloginkeygen -mode rotate-signing -algorithm RS256 `
|
||||
-id-token-ttl 1h -publish-for 2h -dir data/telegram-login
|
||||
go run ./cmd/telegramloginkeygen -mode rotate-code -dir data/telegram-login
|
||||
```
|
||||
|
||||
Run `rotate-signing` separately for RS256, ES256, or EdDSA. `rotate-code` retains old code keys and
|
||||
adds a new active key. Do not edit manifests or PEM files manually, and never generate divergent
|
||||
key rings independently on different instances.
|
||||
|
||||
## 4. PostgreSQL, Redis, files, and seed data
|
||||
|
||||
|
|
@ -95,7 +277,7 @@ The language-pack file manifest is authoritative. To add a language, place `data
|
|||
| `TELESRV_AUTH_CODE_RATE_WINDOW` | duration / `10m` | Shared window for phone and auth-key issuance limits. |
|
||||
| `TELESRV_PHONE_CODE_DELIVERY_PROVIDER` | enum / `development` | `development` uses fixed codes; `webhook` generates random SMS codes for login, registration, and phone changes. Both modes first commit the same code to the durable 777000 dialog for existing accounts; Webhook is additive. |
|
||||
| `TELESRV_EMAIL_CODE_DELIVERY_PROVIDER` | enum / `smtp` | Delivery implementation for login-email and email setup/change codes: `smtp` or `webhook`. Existing-account login-email codes are first mirrored to 777000; setup/change remains provider-only. |
|
||||
| `TELESRV_OTP_WEBHOOK_URL` | absolute URL / empty | Required when any provider selects `webhook`; see [otp-delivery.md](otp-delivery.md) for the fixed v1 contract. Must use `http`/`https` and contain no userinfo. |
|
||||
| `TELESRV_OTP_WEBHOOK_URL` | absolute URL / empty | Required when any provider selects `webhook`; see [otp-delivery.md](otp-delivery.md) for the fixed v1 contract. Any valid `http://` or `https://` host/IP and port is accepted; userinfo is rejected. |
|
||||
| `TELESRV_OTP_WEBHOOK_SECRET` | secret string / empty | Optional HMAC-SHA256 signing secret; enables `X-Telesrv-Signature` when non-empty. |
|
||||
| `TELESRV_OTP_WEBHOOK_TIMEOUT` | duration / `5s` | Webhook HTTP timeout; must be positive when Webhook delivery is enabled. |
|
||||
| `TELESRV_LOGIN_EMAIL_ENABLE` | bool / `false` | Enables login-email verification. SMTP settings are required only when the email provider is `smtp`. |
|
||||
|
|
@ -207,6 +389,19 @@ The following fallback keys are accepted from the **process environment only**.
|
|||
| `TELESRV_STARS_STARTING_GRANT` | int64 / `1000` | Idempotent lazy starting Stars balance for all accounts; `0` disables automatic grant. |
|
||||
| `TELESRV_PREMIUM_SWEEP_INTERVAL` | duration / `1m` | Expired-premium cleanup/push interval. Read paths derive expiry independently. |
|
||||
| `TELESRV_PREMIUM_SWEEP_BATCH` | int / `500` | Maximum expired premium rows processed per sweep. |
|
||||
| `TELESRV_STARGIFT_SWEEP_INTERVAL` | duration / `15s` | Local Star Gift offer/auction lifecycle sweep interval; no blockchain connection is made. |
|
||||
| `TELESRV_STARGIFT_SWEEP_BATCH` | int / `1000` | Maximum offer/auction/outbox work claimed per lifecycle sweep. |
|
||||
| `TELESRV_STARGIFT_TON_STARTING_GRANT` | int64 / `10000000000` | Nanoton granted idempotently on a user's first access to the internal telesrv TON ledger; `0` disables it. This is not an on-chain asset. |
|
||||
| `TELESRV_STARGIFT_TRANSFER_STARS` | int64 / `25` | Stars charged for a collectible transfer; `0` enables the free-transfer RPC. |
|
||||
| `TELESRV_STARGIFT_DROP_DETAILS_STARS` | int64 / `25` | Stars charged to remove a collectible's original sender/message details. |
|
||||
| `TELESRV_STARGIFT_OFFER_MIN_STARS` | int / `1` | Minimum Stars offer snapshotted for user-owned collectibles; `0` disables the offer entry point. |
|
||||
| `TELESRV_STARGIFT_STARS_PROCEEDS_PERMILLE` | int / `1000` | Seller share in Stars sales, in permille; the remainder is recorded as platform commission. |
|
||||
| `TELESRV_STARGIFT_TON_PROCEEDS_PERMILLE` | int / `1000` | Seller share in internal-TON sales, in permille; this affects only the local ledger. |
|
||||
| `TELESRV_STARGIFT_EXPORT_DELAY` | duration / `0s` | Delay snapshotted into `can_export_at` when a collectible is issued. |
|
||||
| `TELESRV_STARGIFT_TRANSFER_DELAY` | duration / `0s` | Delay snapshotted into `can_transfer_at`. |
|
||||
| `TELESRV_STARGIFT_RESELL_DELAY` | duration / `0s` | Delay snapshotted into `can_resell_at`. |
|
||||
| `TELESRV_STARGIFT_CRAFT_DELAY` | duration / `0s` | Delay snapshotted into `can_craft_at`. |
|
||||
| `TELESRV_STARGIFT_CRAFT_CHANCE_PERMILLE` | int / `250` | Per-input local craft success contribution, capped at 1000 permille. |
|
||||
|
||||
## 11. Private calls, group calls, TURN, SFU, and livestream
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue