The admin interface
The admin interface at /admin/ lets administrators manage Users, Groups, Roles, Clients and Scopes and read the audit log in the browser. This page explains how it signs in and why it is built the way it is.
An application like any other
The admin interface has no special access. It is registered as a Client, Authora Admin UI, which Authora creates at startup, and it signs in through the same Authorization Code flow with PKCE as every other application. The admin API then checks its Access Token exactly like any other Client's.
This means the admin API has a single way in. There is no separate admin login and no session-based shortcut that would need its own protection.
Tokens never reach the browser
Single-page applications often keep their tokens in JavaScript. Then any script that runs on the page, e.g. through a cross-site scripting bug or a compromised dependency, can read the tokens and use them from anywhere, long after the page is closed.
The admin interface avoids this with a small backend for frontend inside Authora:
- The server runs the flow, keeps
stateand the PKCE verifier, and exchanges the code itself. - The tokens live only in an encrypted,
HttpOnlycookie. JavaScript cannot read it. - For each
/api/*request, Authora turns the cookie into a Bearer token before authentication, so the admin API code is unchanged.
A malicious script could still act as the administrator while the page is open, but it cannot take the tokens away. The strict Content Security Policy is what keeps such scripts out in the first place.
Protection against cross-site requests
A cookie that grants API access invites cross-site request forgery. The admin API therefore accepts the cookie only with the header X-Authora-Admin: 1. Browsers cannot send a custom header to another origin without a CORS preflight, and /api/* never allows one. The cookie is also SameSite=Strict, and requests whose Sec-Fetch-Site header says they come from another site are ignored.
Bound to the Session
The admin interface's tokens are tied to the Authora Session the administrator signed in with. A refresh only works while that Session is valid; otherwise Authora revokes the admin interface's Grant and the administrator signs in again.
This does not cut off access at once in every case:
- If the Session expires (idle timeout or absolute lifetime) or the administrator signs out of Authora in another tab, the Access Token already in the cookie stays usable until it expires (1 hour by default). Only the next refresh fails.
- If the User is signed out everywhere, deactivated or deleted, or gets a new password, their tokens are invalid immediately, because every token check compares the User's security stamp.
To remove an administrator's access right away, use Sign out everywhere or Deactivate, not a Session timeout.
Refreshing safely across tabs
All tabs share one cookie, and a Refresh Token used twice revokes the whole Grant. The interface therefore refreshes in one tab at a time (using the Web Locks API), and the server skips a refresh if another tab did one in the last ten seconds.
Why no consent screen
The admin interface is a first-party Client, so administrators are not asked for consent on every sign-in. See Security model for why that is safe and what protects it.
Hiding what you may not do
GET /api/me returns the User's Permissions, and the interface hides buttons for actions the User may not perform. This is only for convenience. The API checks every Permission on every request, whatever the interface shows.
No build step
The interface is plain HTML, CSS and JavaScript modules in src/Authora.Api/wwwroot/admin, with no framework and no build step. All content is inserted as text, never as HTML, so names from the API cannot inject markup. The small code base and the absence of third-party scripts keep the attack surface small.
Turning it off
Set Authora:AdminUi:Enabled to false to serve 404 for /admin/*. The admin API keeps working for other Clients allowed authora.admin.