diff options
| author | Leitwolf11 | 2026-10-23 11:02:39 +0300 |
|---|---|---|
| committer | Leitwolf11 | 2026-10-23 11:02:39 +0300 |
| commit | 9099e9fbb50d27b622362b0c2f0dda5085d1fa03 (patch) | |
| tree | 7d4905828cf0ff34c446025529f3adafa797a86f /docs | |
| parent | 3481b5fe411fb3aa5898b0965e42cc852f3d690c (diff) | |
| download | progmaweb-9099e9fbb50d27b622362b0c2f0dda5085d1fa03.tar.gz | |
Move the OAuth pages to Next.js and split the authorize host and the console
Progmasoft OAuth now runs on three hosts:
- credentials.progmasoft.com stays the issuer: discovery documents, key
set, token, user information, revocation and introspection.
- authorize.progmasoft.com serves the pages people see: the
authorization and end session endpoints (registered with OpenIddict as
absolute URIs on that host), sign-in, the consent screen and the
applications an account has allowed.
- console.progmasoft.com is the Progmasoft Console. Its overview links
the areas; OAuth 2.1 tokens live under /credentials, with New token,
then the application type, then its form.
The console has no sign-in of its own and never redirects. It uses the
Progmasoft account session, so production now shares that cookie with
progmasoft.com (__Secure-ProgmasoftSession, Domain=progmasoft.com,
HttpOnly, Secure, SameSite=Lax). Without AccountSessions:CookieDomain the
cookie stays host-only with the __Host- name, as in development and tests.
Application types replace the confidential/public switch: web,
single-page, desktop, mobile and service. Each type has its redirection
rules (RFC 8252), its secret or none, and its grants; only a service
uses client credentials and it registers no address or scope. The type is
kept as an application property and cannot change.
The HTML pages of the API are gone. The pages are Next.js pages in four
languages (en-US, de-DE, ru-RU, he-IL) that call JSON endpoints under
/api/v1/oauth. Requests that change state must come from the page's own
origin; antiforgery forms are no longer needed. The token, revocation and
user information endpoints answer CORS requests from the origins of
single-page applications, without credentials; the discovery documents
and the key set answer every origin.
The host filter keeps every path on its host. Nginx gains the authorize
and console virtual hosts, and the docs describe the hosts, the types and
the shared session.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/ACCOUNT-API.md | 10 | ||||
| -rw-r--r-- | docs/OAUTH.md | 85 | ||||
| -rw-r--r-- | docs/README.md | 2 | ||||
| -rw-r--r-- | docs/api/namespaces/Progmasoft.OAuth.Api.md | 9 | ||||
| -rw-r--r-- | docs/api/namespaces/Progmasoft.OAuth.Developers.md | 2 | ||||
| -rw-r--r-- | docs/api/namespaces/Progmasoft.OAuth.Pages.md | 9 |
6 files changed, 72 insertions, 45 deletions
diff --git a/docs/ACCOUNT-API.md b/docs/ACCOUNT-API.md index 68186b5..51648a3 100644 --- a/docs/ACCOUNT-API.md +++ b/docs/ACCOUNT-API.md @@ -120,9 +120,14 @@ to `/login?google=failed`, and the callback path is not a route. | Cookie | Purpose | Attributes | | --- | --- | --- | -| `__Host-ProgmasoftSession` | the account session | `HttpOnly`, `Secure`, `SameSite=Lax`, `Path=/`, expires with the session | +| `__Secure-ProgmasoftSession` | the account session | `HttpOnly`, `Secure`, `SameSite=Lax`, `Path=/`, `Domain=progmasoft.com`, expires with the session | | `__Host-ProgmasoftExternal` | carries the Google identity between callback and completion | `HttpOnly`, `Secure`, `SameSite=Lax`, ten minutes | +In production the session cookie is shared with `progmasoft.com`, so that the Progmasoft Console on +`console.progmasoft.com` knows the signed-in account without a sign-in of its own; a cookie with a domain takes the +`__Secure-` prefix instead of `__Host-`. Without `AccountSessions:CookieDomain` the cookie belongs to the account host +alone and keeps the `__Host-` name. + A session token is 256 random bits. The service stores only its SHA-256 digest, so a copy of the store does not contain a usable token. A session lasts 30 days (720 hours) from the sign-in, whether the account signed in with a password or with Google; `AccountSessions:LifetimeHours` changes that, within 1 to 720 hours. @@ -143,7 +148,8 @@ The client address comes from `X-Forwarded-For`, which the service accepts from | Setting | Meaning | Default | | --- | --- | --- | | `AccountSessions:LifetimeHours` | hours a session stays valid, clamped to 1–720 | `720` | -| `AccountSessions:CookieName` | name of the session cookie | `__Host-ProgmasoftSession` | +| `AccountSessions:CookieName` | name of the session cookie | `__Host-ProgmasoftSession`; production `__Secure-ProgmasoftSession` | +| `AccountSessions:CookieDomain` | domain the session cookie is shared with | none; production `progmasoft.com` | | `Authentication:Google:ClientId` | Google OAuth client identifier | empty; Google sign-in is off | | `Authentication:Google:ClientSecret` | Google OAuth client secret | empty; Google sign-in is off | | `AllowedHosts` | host names the service answers | see `appsettings.json` | diff --git a/docs/OAUTH.md b/docs/OAUTH.md index 3b14fde..31a88ac 100644 --- a/docs/OAUTH.md +++ b/docs/OAUTH.md @@ -4,50 +4,71 @@ # Progmasoft OAuth Progmasoft OAuth lets any application sign people in with their Progmasoft account and, with their consent, act on -their behalf. It is an OAuth 2.1 authorization server and an OpenID Connect provider at -`https://credentials.progmasoft.com/`. Any developer with a Progmasoft account can register applications. +their behalf. It is an OAuth 2.1 authorization server and an OpenID Connect provider on three hosts: -## Register an application +| Host | Serves | +| --- | --- | +| `credentials.progmasoft.com` | The issuer (`https://credentials.progmasoft.com/`): discovery documents, key set, and the endpoints clients call directly | +| `authorize.progmasoft.com` | The pages people see: the authorization endpoint with sign-in and the consent screen, the end session endpoint, and the applications an account has allowed | +| `console.progmasoft.com` | The Progmasoft Console, where developers make tokens for their applications | -Sign in at `https://credentials.progmasoft.com/developers` and register the application: +The console has no sign-in of its own: it uses the Progmasoft account session of `account.progmasoft.com`, so any +developer signed in to their Progmasoft account can make tokens there. -| Field | Meaning | -| --- | --- | -| Type | **Confidential** for a server that keeps a client secret; **public** for a browser or native application, which has no secret. The type cannot change later. | -| Name | What the consent page shows, 3 to 64 characters. | -| Homepage | Optional, `https://` only. | -| Redirection addresses | Up to 10, compared exactly. `https://` addresses; `http://` only for a loopback address (`127.0.0.1`, `[::1]`, `localhost`); for public clients also a private-use scheme in reverse DNS order, such as `com.example.app:/callback` (RFC 8252). No fragments, user information or wildcards. | -| Addresses after sign-out | Optional, the same rules; where `/connect/logout` may send the account holder. | -| Scopes | The scopes the application may request; see below. | -| Service access | Allows the client credentials grant; confidential clients only. | - -The portal shows the client identifier (`pmo_…`) and, for a confidential client, the client secret. The secret is -shown once and stored only as a hash; make a new one in the portal if it is lost. An account can register 10 -applications. Deleting an application ends every authorization and token it holds. +## Make a token + +Open **OAuth 2.1 tokens** in the console (`/credentials`), choose **New token**, then the type of the application. The type decides how the application +proves itself, which grants it may use and where people may return; it cannot change later. + +| Type | For | Secret | Grants | Redirection addresses | +| --- | --- | --- | --- | --- | +| Web application | A site with a server | Yes | Authorization code + PKCE, refresh | `https://`; `http://` loopback during development | +| Single-page application | A browser application without a server | No | Authorization code + PKCE, refresh | `https://`; `http://` loopback during development | +| Desktop application | A desktop or command-line program | No | Authorization code + PKCE, refresh | `http://` loopback (`127.0.0.1`, `[::1]`, `localhost`) or a private-use scheme | +| Mobile application | An iOS or Android application | No | Authorization code + PKCE, refresh | A private-use scheme or a claimed `https://` address | +| Service | A server that acts as itself | Yes | Client credentials | None | + +A private-use scheme names the application in reverse DNS order, such as `com.example.app:/callback` (RFC 8252). +Addresses are compared exactly; fragments, user information and wildcards are refused. Up to 10 redirection addresses +and 10 addresses after sign-out (where `/connect/logout` may send the account holder) are registered per application. + +Every type but a service also lists the scopes the application may request (see below); each person still decides on +the consent page. The name (3 to 64 characters) is what the consent page shows; the homepage is optional and +`https://` only. + +The console shows the client identifier (`pmo_…`) and, for a type with a secret, the client secret. The secret is +shown once and stored only as a hash; make a new one in the console if it is lost. An account can have 10 tokens. +Deleting an application ends every authorization and token it holds. + +### Single-page applications + +The token, revocation and user information endpoints answer CORS requests from the origins of the redirection +addresses that single-page applications registered, without credentials. The discovery documents and the key set +answer every origin. ## Endpoints The discovery documents list everything: `/.well-known/openid-configuration` and `/.well-known/oauth-authorization-server`. -| Endpoint | Path | +| Endpoint | Address | | --- | --- | -| Authorization | `/connect/authorize` | -| Token | `/connect/token` | -| User information | `/connect/userinfo` | -| End session | `/connect/logout` | -| Revocation | `/connect/revoke` | -| Introspection | `/connect/introspect` (confidential clients) | -| Key set | `/.well-known/jwks` | +| Authorization | `https://authorize.progmasoft.com/connect/authorize` | +| End session | `https://authorize.progmasoft.com/connect/logout` | +| Token | `https://credentials.progmasoft.com/connect/token` | +| User information | `https://credentials.progmasoft.com/connect/userinfo` | +| Revocation | `https://credentials.progmasoft.com/connect/revoke` | +| Introspection | `https://credentials.progmasoft.com/connect/introspect` (web applications and services) | +| Key set | `https://credentials.progmasoft.com/.well-known/jwks` | ## Flows -- **Authorization code with PKCE**, for every client. `code_challenge_method` must be `S256`; requests without a - challenge, and `plain` challenges, are refused. Confidential clients also authenticate at the token endpoint with - their secret (`client_secret_post` or `client_secret_basic`). +- **Authorization code with PKCE**, for every type but a service. `code_challenge_method` must be `S256`; requests + without a challenge, and `plain` challenges, are refused. Web applications also authenticate at the token endpoint + with their secret (`client_secret_post` or `client_secret_basic`). - **Refresh tokens**, with `offline_access`. Each refresh returns a new refresh token and retires the old one. A retired refresh token that is presented again is treated as stolen: the whole chain of tokens is revoked. -- **Client credentials**, when allowed. The token names the application itself (`sub` is the client identifier) and +- **Client credentials**, for services. The token names the application itself (`sub` is the client identifier) and carries no account scope. The implicit grant, the resource owner password grant and the device flow are not offered. @@ -77,7 +98,7 @@ the application's name, the account that registered it, and the host the account that already holds consent for the requested scopes gets its code without the page, unless it sends `prompt=consent`. `prompt=none` returns `login_required` or `consent_required` instead of showing a page. -Account holders review and withdraw consent at `https://credentials.progmasoft.com/account/applications`. +Account holders review and withdraw consent at `https://authorize.progmasoft.com/account/applications`. Withdrawing ends the application's tokens at once. ## Tokens @@ -95,5 +116,5 @@ their content. ## Limits -The token endpoint, the authorization endpoint and the portal accept 60 requests a minute from one address; the -sign-in form accepts 12 in three minutes. More are answered with 429. +The token endpoint, the authorization endpoint and the console accept 60 requests a minute from one address; the +sign-in forms accept 12 in three minutes. More are answered with 429. diff --git a/docs/README.md b/docs/README.md index e597b08..d681f6d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -10,7 +10,7 @@ so; [Known limitations](LIMITATIONS.md) collects those places. | --- | --- | | [Architecture](ARCHITECTURE.md) | which process serves which host, how a request travels, and where the trust boundaries are | | [Account API](ACCOUNT-API.md) | every endpoint of the account service: requests, responses, errors, cookies and limits | -| [OAuth](OAUTH.md) | Progmasoft OAuth for developers: registering applications, flows, scopes, consent, tokens and limits | +| [OAuth](OAUTH.md) | Progmasoft OAuth for developers: tokens in the Progmasoft Console, application types, flows, scopes, consent, tokens and limits | | [Localization](LOCALIZATION.md) | which languages are published, how a page picks one, how Hebrew is laid out, and how to add a language | | [Development](DEVELOPMENT.md) | how to run, test and document the project locally, and what each CI check enforces | | [Known limitations](LIMITATIONS.md) | what is deliberately missing or temporary, and what that means for operations | diff --git a/docs/api/namespaces/Progmasoft.OAuth.Api.md b/docs/api/namespaces/Progmasoft.OAuth.Api.md new file mode 100644 index 0000000..6b657d1 --- /dev/null +++ b/docs/api/namespaces/Progmasoft.OAuth.Api.md @@ -0,0 +1,9 @@ +--- +uid: Progmasoft.OAuth.Api +summary: *content +--- + +<!-- SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com> --> +<!-- SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 --> + +The JSON endpoints under `/api/v1/oauth` that the pages of credentials.progmasoft.com and console.progmasoft.com call: sign-in, consent, the allowed applications, the applications of the console, and the CORS rule for single-page applications. diff --git a/docs/api/namespaces/Progmasoft.OAuth.Developers.md b/docs/api/namespaces/Progmasoft.OAuth.Developers.md index 503b35e..e9106ab 100644 --- a/docs/api/namespaces/Progmasoft.OAuth.Developers.md +++ b/docs/api/namespaces/Progmasoft.OAuth.Developers.md @@ -6,4 +6,4 @@ summary: *content <!-- SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com> --> <!-- SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 --> -The developer portal: the rules an application registration follows, the registry that keeps applications per account, and the portal pages. +The applications of the Progmasoft Console: their types, the rules each type follows, and the registry that keeps applications per account. diff --git a/docs/api/namespaces/Progmasoft.OAuth.Pages.md b/docs/api/namespaces/Progmasoft.OAuth.Pages.md deleted file mode 100644 index b8700aa..0000000 --- a/docs/api/namespaces/Progmasoft.OAuth.Pages.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -uid: Progmasoft.OAuth.Pages -summary: *content ---- - -<!-- SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com> --> -<!-- SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 --> - -The HTML pages of the OAuth host: sign-in, the home page, the applications an account has allowed, and the renderer with its content security policy. |