Trace identity from password verification to delegated tokens, then enforce access on every object request.
55 min 180 XPSkills: Identity flows, Session security, Object authorisation
Brief
At Halcyon Clinics, a patient signs in with a password and a second factor, then changes the invoice number in a request from 410 to 411. Another patient's invoice appears. The delivery lead calls this a broken login, although the identity service correctly identified the patient. The missing decision was whether that identified patient could read that specific invoice.
Authentication establishes who is acting; authorisation decides whether that actor may perform an action on a resource in the current context. This room follows both boundaries: protecting stored credentials, maintaining sessions, delegating API access, and checking resource ownership. Your evidence package must show more than a successful login: an auditor needs unsuccessful cross-patient tests, expiry tests and policy decisions without secret-bearing logs.
A valid identity, a valid token and permission to read a particular record are three different claims.
Passwords and independent factors
Never store recoverable passwords or fast general-purpose digests. Store a unique random salt, a slow password hash, the algorithm and its work parameters per credential. bcrypt uses a cost setting; scrypt and Argon2 use memory as well as computation to make bulk guessing expensive. Two identical passwords with different salts produce different stored values. Salts are not secrets: they defeat precomputed tables, not guessing against one account. An illustrative target of 200-500 ms per verification must be benchmarked under peak load; rate limiting is still necessary to resist online guessing and resource exhaustion. Rehash after a successful login when parameters become outdated, and account for bcrypt's common 72-byte input limit rather than silently truncating long passwords.
MFA combines different factor categories: knowledge, possession and inherence. A password plus a PIN is still one category. One-time codes add a possession factor but can be phished; origin-bound public-key authentication offers stronger phishing resistance. Recovery and factor replacement must not downgrade protection: single-use recovery codes, recent reauthentication and notifications matter as much as enrolment. For credential-protection controls, retain parameter configuration, benchmark results and enrolment/recovery test records. An auditor should ask whether a help-desk reset bypasses the factors enforced at normal login, not merely how many users enrolled.
Sessions carry yesterday's authentication into today's request
After login, a browser commonly receives a random opaque session identifier whose server-side record contains the subject and expiry. Rotate the identifier at login and privilege elevation so an attacker cannot fix a known pre-login identifier. Use TLS and cookies marked Secure and HttpOnly with an appropriate SameSite setting; HttpOnly limits script access, not malicious requests made by injected scripts. SameSite is defence in depth: state-changing cookie-authenticated requests still need suitable CSRF protection and origin checks. Do not put session secrets in URLs or logs.
An illustrative policy expires sessions after 15 idle minutes and at an absolute age of 8 hours, even if activity continues. Enforce both on the server; a browser timer is not a control. Logout invalidates the server session, and a password reset can invalidate all active sessions. Self-contained access tokens may remain valid until expiry unless a revocation mechanism exists, so define that residual window. Evidence should include attempted reuse of an old identifier after login, logout and expiry, with timestamps and redacted correlation identifiers. Ask: can a copied credential still work after the user believes access ended?
Delegation is not a login protocol
OAuth 2.0 delegates access to a resource server; OIDC adds authentication through an ID token and identity claims. An access token is intended for its API audience, whereas an ID token is intended for the client that requested sign-in. Validate signatures using trusted keys and allowed algorithms, issuer, audience and expiry; validate the OIDC nonce when used. An API must not accept an ID token just because it is signed. Scopes such as invoices:read bound delegated operations, but do not prove ownership of invoice 411. A scope is a ceiling, not a substitute for application policy.
In the authorisation code flow with PKCE, the client generates a high-entropy verifier and sends its S256 challenge with the authorisation request. The authorisation server returns a short-lived, single-use code to an exactly registered redirect URI. The client exchanges the code plus verifier at the token endpoint; the server recomputes the challenge and rejects a mismatch. A stolen code alone is insufficient. Bind the response to the initiating browser transaction, commonly with state; PKCE is not permission to ignore redirect validation or transaction binding. Confidential clients also authenticate at the token endpoint. Refresh tokens require protected storage, rotation where supported and reuse detection. Capture redacted flow traces and wrong-verifier, wrong-audience and expired-token tests for assurance, never live codes or tokens.
PKCE binds code redemption to the initiating client; token audience still determines where each token belongs.
Roles, attributes and the object boundary
RBAC assigns permissions to roles, then roles to subjects: a billing reader may view invoices while a billing manager may approve refunds. ABAC evaluates attributes of subject, object, action and environment: allow reading only if the subject's clinic matches the invoice's clinic and the treatment relationship remains active. Combine them where useful: a role grants the category of action, while attributes restrict the records and circumstances. Deny by default when required attributes are absent; retrieve authoritative attributes rather than trusting a submitted clinic identifier.
IDOR occurs when a caller changes a direct object reference and the server fails to enforce access to the resulting object. Unpredictable identifiers reduce discovery but do not repair authorisation. For GET /invoices/411, resolve the authenticated subject, validate the token and required scope, and query or check the object against that subject's permitted tenant and relationship before returning data. Repeat this at every read, update, export and bulk endpoint; hiding a button is not enforcement. Evidence for least privilege includes a role-permission matrix, versioned attribute policies and negative tests using two subjects in different clinics. Ask the auditor's practical question: what prevents an authenticated user from requesting a neighbour's record directly?
Passing the role and scope gates does not bypass the object-level clinic boundary.
Tasks
Answers are graded on the server: the answer key never reaches your browser.
Task 1: Two secrets, one category
Scenario sim+60 XP
Read the brief and answer both questions.
Incident brief
Halcyon stores passwords using a slow password algorithm but reuses one public value for every account. The engineer calls this value an encryption key. Meanwhile, the login team claims a password followed by a memorised PIN is MFA. Both steps are verified correctly; neither relies on a device or biological trait.
Term bank, not all of these are right
saltknowledgeencryptionpossession
1.1What per-password random value must replace the shared value? (one word)
1.2Which factor category do both the password and PIN belong to? (one word)
Task 2: The signed-token shortcut
Scenario sim+60 XP
Read the brief and answer both questions.
Incident brief
A browser client requests sign-in through OAuth 2.0 plus an identity layer. Its developer sends the resulting identity assertion to an API as though it were an access token: 'Anything signed by our issuer is valid everywhere.' A tester also intercepts a code, but cannot redeem it because the token endpoint requires proof tied to the client's original challenge.
Term bank, not all of these are right
OIDCPKCERBACOAuth 2.0
2.1Which identity layer supplies the sign-in semantics? (one acronym)
2.2Which code-flow extension explains why the intercepted code alone is insufficient? (one acronym)
Task 3: Authorised reader, unauthorised invoice
Scenario sim+60 XP
Read the brief and answer both questions.
Incident brief
A billing reader with invoices:read changes /invoices/410 to /invoices/411 and reads another clinic's invoice. The team says the role and scope already authorise the request. The proposed repair retains the reader role but also compares the subject's clinic and treatment relationship with authoritative object attributes on every request.
Term bank, not all of these are right
IDORABACRBACMFA
3.1What vulnerability does changing the reference expose? (one acronym)
3.2Which access-control model describes the added attribute comparisons? (one acronym)
Labs
80 bonus XP
Hands-on work. You edit the artefact, the server runs the checks: the expectations and the reference solution never reach your browser.
Halcyon's release owner proposes reversible password storage so support can recover forgotten passwords, and an eight-hour browser timer as the entire expiry control. They also say the API should accept any signed identity token.
Write the replacement YAML contract from the requirements below. This is a declarative control specification, not executable security middleware; each field must express the server-enforced requirement, with negative tests implemented separately.
Approved requirements and current shortcuts
Password storage: choose bcrypt, scrypt or argon2; unique random salt per credential.
Session: server-enforced idle limit exactly 15 minutes; absolute limit exactly 480 minutes; rotate at login; invalidate on logout.
Browser cookie: Secure and HttpOnly required.
Delegation: authorization_code flow with S256 PKCE; API accepts access_token only.
Invoice access: server-side ownership/tenant check required; default deny.
Current shortcut: browser hides foreign invoices but API fetches by identifier alone.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Checks
Password verifier uses a slow algorithm and unique salt
Both server-side expiry limits match the contract
Login rotation and logout invalidation are required
Browser cookie blocks insecure transport and script reads
Code redemption uses PKCE and the API receives the right token
The release owner says every item is safe because the sign-in screen requires MFA. Review each independent claim against the described implementation; do not infer protections that are not stated.
Accept claims that are technically sound. Reject flawed claims using exactly one root-cause code: weak-storage for unsuitable password storage, factor-category for non-independent factors, token-purpose for using the wrong token at an API, or object-boundary for missing server-side object checks.
Verdicts are accept or reject. Every rejection needs one reason code from: weak-storage | factor-category | token-purpose | object-boundary.
Release claims with implementation facts
AA-1 Passwords use a fast unsalted digest; TLS makes database disclosure harmless.
AA-2 Password plus memorised PIN counts as two independent MFA factors.
AA-3 API accepts an ID token intended for the browser client because its signature is valid.
AA-4 Invoice download checks only invoices:read; hidden links prevent cross-clinic access.
AA-5 Server rotates session identifiers at login, rejects the old identifier, and invalidates the current session on logout.
AA-6 Role grants invoice reading, while a server-side policy denies requests with a mismatched clinic or missing relationship attribute.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Checks
Every line in the fixture carries a verdict
Accept and reject land on the right lines
Each rejection cites a valid reason code
Next on your path · Application Fundamentals
The Secure SDLC
Turn application risks into testable requirements, threat models, complementary tests and evidence-backed release decisions.