Staff sign-in
Back in Middleware, the back office got a shared STAFF_TOKEN. Everyone knows it, it never changes, and the audit log can't tell staff members apart. The box office has real accounts and its own OpenID Connect provider now, so the back office can sign staff in exactly like the fan club signs fans in: by being a client of the box office.
Staff members
A staff member is a customer with a name the staff know them by. Its primary key is the customer's key:
use Key;
use model;
use OnDelete;
use crateCustomer;
A command adds them:
$ box_office add-staff-member ana@example.com --display-name Ana
Ana can sign in to the back office as ana@example.comA client of its own provider
The back office lives in the same application as the provider. Admit it as a client, and let it sign in with keys the application already has, ClientKeys::Own. Staff shouldn't have to approve their own back office, so consent is Implicit. The back office only needs to know who signed in, so it asks for openid and needs no resources:
use ClientKeys;
use ConsentPolicy;
use IdTokenSigning;
use admits_oauth_client;
use ClientAuthenticationMethod;
use OpenidScope;
use crateFinishStaffSignIn;
;redirect_routes names the callback route by its type, so the redirect address can never drift from the route. Then declare the client side, pointing at the admitted client:
use oauth_client;
;Sign-in routes
The back office signs staff in with the same two routes as Sign in with Google, on the admin server:
;
;Only staff members get in. The ID token's subject is the customer's id, because the box office issued it:
IgnoredAny from serde says the back office needs no claims beyond the subject. A staff member who's already signed in at the box office goes straight through. Anyone else signs in at the box office first, with a link or with Google.
Who is signed in
The back office asks for a StaffMember, from its own provider. It uses all three outcomes: no session sends the browser to the staff sign-in, a session of someone who isn't staff gets a 403, and a staff member is let in:
pub async Customer and StaffMember both come from the same sessions, through two different providers. A route asks for one of them, never both.
Replacing the shared token
Every admin route drops #[middleware(staff_only)] and asks for the staff member instead. The dashboard greets them by name:
The staff_only middleware, the StaffToken, its cookie, its sign-in form, and the STAFF_TOKEN variable all go away. audit_log stays. The staff sign out with a route of their own, which lands back on the staff sign-in:
;$ curl -i https://admin.tickets.internal/
HTTP/1.1 303 See Other
location: https://admin.tickets.internal/sign-in
$ curl -i https://admin.tickets.internal/sign-in
HTTP/1.1 303 See Other
location: https://tickets.example.com/authorize?response_type=code&client_id=back-office&state=...&redirect_uri=https%3A%2F%2Fadmin.tickets.internal%2Fsign-in%2Fcallback&scope=openid&code_challenge=...&code_challenge_method=S256&nonce=...
Session cookies are host-only, so the public site and the back office each keep their own session. Give them separate host names, both served over HTTPS.