Built-in OAuth2 consent-challenge handler (todo §6); /oauth2/consent grants scopes to a client logging in through us. New src/oauth-consent.ts (pure, sibling of oauth-login.ts): resolveConsentChallenge auto-accepts a first-party client (Hydra metadata.first_party===true) or a Hydra-skipped one, else returns a view to show the themed consent screen; acceptConsent re-reads the challenge so scopes/audience are never client-supplied; rejectConsent → access_denied. The grant carries an OIDC session.id_token with email/name projected from the Kratos identity (whoami traits, omitted when absent). src/hydra-admin.ts gains the consent half (get/accept/reject consent + types; login/consent URL builder folded into one reqUrl(kind,…) + shared put()). Wired in app.ts at GET|POST /oauth2/consent (gated on hydra+kratos): GET shows/auto-accepts (sets the CSRF cookie when fresh), POST is CSRF-guarded (same signed double-submit as /logout) and dispatches allow→accept / else→reject → 303 to Hydra; a stale/consumed challenge (Hydra 4xx) degrades to a recoverable 400, a real outage (5xx) → 500 (mirrors /oauth2/login). views/oauth-consent.ejs + partials/consent-body.ejs reuse the auth-card, listing the requested scopes (friendly labels for the standard OIDC ones) with Allow/Deny submit buttons. Tests-first: hydra-admin consent contracts + oauth-consent skip/first-party/third-party/audience/id_token/refetch/reject matrix + app HTTP integration (auto-accept / screen+CSRF cookie / allow+deny / forged-CSRF→403 / missing→400 / stale→400 / outage→500). Stability-reviewer run as a local PR: APPROVE, no Critical/High. Extended e2e/oauth-login.spec.ts to drive the whole authorization-code flow against real Hydra — login accept → follow login_verifier through Hydra → web's consent screen (third-party e2e-login, scopes listed) → Allow → consent_verifier → client callback with a real code (per-host cookie jars, Hydra resume URLs rebased onto the compose host). typecheck + 262 units + 8 visual + OAuth login+consent E2E green. OAuth2 client registration is the next §6 item.
This commit is contained in:
@@ -11,10 +11,14 @@ const SUBJECT = "01902d5e-7b6c-7e3a-9f21-3c8d1e0a4b55";
|
||||
const SELF = "http://127.0.0.1:3000/oauth2/login?login_challenge=chal-1";
|
||||
|
||||
function stubHydra(login: LoginRequest, capture?: (b: AcceptLogin) => void): HydraAdmin {
|
||||
const unused = async () => { throw new Error("unused"); };
|
||||
return {
|
||||
acceptConsentRequest: unused,
|
||||
acceptLoginRequest: async (_c, body) => { capture?.(body); return { redirect: "http://hydra/oauth2/auth?login_verifier=v" }; },
|
||||
getConsentRequest: unused,
|
||||
getLoginRequest: async () => login,
|
||||
rejectLoginRequest: async () => { throw new Error("unused"); },
|
||||
rejectConsentRequest: unused,
|
||||
rejectLoginRequest: unused,
|
||||
};
|
||||
}
|
||||
const stubKratos = (whoami: KratosPublic["whoami"]): KratosPublic => ({
|
||||
|
||||
Reference in New Issue
Block a user