Logout and notifications
RP-initiated logout (end_session)
GET /oauth2?op=end_session id_token_hint (the user's most recent id_token) post_logout_redirect_uri (registered in the portal; state passthrough supported)
With both parameters the U session ends and the browser returns to your page. Without them the standard U sign-out page runs.
Back-channel logout (recommended)
When the user signs out anywhere - your app, another app, or their U account - we POST a signed Logout Token to your registered back-channel endpoint:
POST your-endpoint (application/x-www-form-urlencoded) logout_token=<JWT>
The token is RS256 with the same keys as id_tokens (verify against the JWKS) and carries iss, sub, aud (your client_id), iat, exp (120s), jti (unique - reject replays), and events. Respond 2xx quickly; we retry at 1m, 5m, 30m, 2h, 6h, then stop.
Verifying a Logout Token (PHP)
$parts = explode(".", $_POST["logout_token"]);
$claims = json_decode(base64_decode(strtr($parts[1], "-_", "+/")), true);
if (($claims["iss"] ?? "") !== "https://accounts.u.cash") exit("no");
if (($claims["aud"] ?? "") !== MY_CLIENT_ID) exit("no");
if (($claims["exp"] ?? 0) < time()) exit("no");
if (!isset($claims["events"]["http://schemas.openid.net/event/backchannel-logout"])) exit("no");
// 1. fetch /.well-known/jwks.json, pick the kid from the token header
// 2. openssl_verify(parts[0].".".parts[1], sig, pem_from_jwk, "sha256")
// 3. reject a jti you have seen before
http_response_code(200); // then clear the user's local session
Discovery advertises backchannel_logout_supported: true and backchannel_logout_session_supported: false (a logout applies to the subject, not to a per-app session).