The Organization Console¶
The organization console is where people administer an organization for
every application at once: its connections to external services first, and
its members, roles and access as they join. SystemAuth serves it under
/console on its own host, signed in with the SystemAuth login session. The
design is ADR-018.
Enable the console¶
Add a console section to the SystemAuth configuration. The console signs
in with social login's session, so social_login must be configured too.
social_login:
github:
client_id: ${SYSTEMAUTH_GITHUB_CLIENT_ID}
client_secret: ${SYSTEMAUTH_GITHUB_CLIENT_SECRET}
console:
web_dir: /opt/myapp/web/console
| Key | Meaning |
|---|---|
web_dir |
Directory of the console's built pages, with an index.html. Empty serves only the console's API |
The connections section appears when connections are
enabled. Startup fails when console is set without social_login, or when
web_dir has no index.html.
Build the pages¶
The pages are a static build of @plexusone/console from
systemforge-web, built by
the host application with its own chrome and with /console/ as the base
path. Point web_dir at the output. The console serves:
- each file under
web_dir; files underassets/are cached as immutable, others revalidated; index.htmlfor every other path under/console/, never cached, after sending a person without a session to/login?return_to=<the page>.
Every response carries a content security policy that allows only the console's own scripts and connections, and refuses framing.
API¶
The session routes under /console/bff speak the format @plexusone/auth's
SessionClient reads from a backend-for-frontend, so the pages run in
createHost from @plexusone/host like any application:
| Call | Does |
|---|---|
GET /console/bff/session |
The person and their organizations, personal first, and the deployment's app catalog. Each organization grants the application console with the person's organization role, besides their roles in the products, so the console's product switcher links back to them. Without a session: {"authenticated":false} |
GET /console/bff/auth/login?return_to= |
Sends the person to /login, and back to return_to, a path on this host |
GET /console/bff/auth/{provider}?return_to= |
The same, straight to that provider's sign-in |
POST /console/bff/auth/logout |
Signs the person out of SystemAuth, as POST /logout does, and answers 204 |
The console's API is under /console/api, authenticated by the login
session. A request without one gets 401 {"error":"sign in required"}.
| Call | Returns |
|---|---|
GET /console/api/v1/return-to?url= |
The return address, when sign-in's redirect policy allows it, else 400 |
/console/api/v1/providers and /console/api/v1/organizations/{org}/connections/... |
The connections API, unchanged; 404 when connections are not enabled |
OAuth scopes do not apply to the console: it is SystemAuth's own interface acting as the signed-in person. Every call is authorized by the person's organization role and grants, as any caller's is, with the organization in the path as the row-level security tenant.
Cross-site requests are refused. A state-changing request must be
same-origin, judged by Sec-Fetch-Site, or by Origin against the host,
using Go's http.CrossOriginProtection. Browsers send these headers; a
script on another site cannot make a state-changing request with the
person's session.
Link from an application¶
An application links to the console instead of hosting administration pages.
A link can carry a return address, which the pages check with
/console/api/v1/return-to before sending the person back:
https://auth.example.com/console/orgs/{org}/connections/new?provider=cloudflare&return_to=https://app.example.com/sites/new
return_to passes when it is a path on the SystemAuth host or a URL on one
of social_login.allowed_redirect_origins.
An application can link to the console from its chrome by listing it in the
app catalog with the ID console and the console's URL. Nobody holds a role
"in" it as a product, so product switchers leave it out; a shell can offer it
as an organization settings entry instead.