Repository navigation
feat: v0.20 adapter: recovery sessions, account notices, placeholder secrets and console headers - #13
Merged
Merged
Conversation
…console proxy The console proxy forwarded only Content-Type, Cache-Control, ETag and Last-Modified, so the API's X-Frame-Options, Content-Security-Policy and X-Content-Type-Options were dropped and the console served on the app origin could be framed. Forward those three headers too. Closes #11
The starters' example cookie secret and the portal's service token placeholder are long enough to pass the length check, so a deployment that never replaced them booted. build() now refuses dev-only-cookie-signing-key-replace-me, GRAB_FROM_SEAMLESS_AUTH_PORTAL_DEV and anything containing replace-me for either secret, unless insecure_cookies is on for local development. Refs fells-code/seamless-auth-server#231
… enrollment An access token from a recovery code or self-service recovery carries recovery: true. require_auth now answers it with 403 enrollment_required unless the layer is built with allow_recovery(true), and User gains a recovery field so authenticate() callers can tell. After a recovery session finishes passkey registration or TOTP enrollment in cookie transport, the adapter refreshes the session in the same response so the access cookie drops the claim. A failed refresh leaves the enrollment answer as it was. Refs fells-code/seamless-auth-server#232
…overy routes Delivery carries the account notice kinds (account_notice_email and account_notice_sms, with subject, text, notice and cancel_url) and the purpose an OTP code may carry. Debug output redacts text and cancel_url, which hold the cancel credential. With deliver_account_notices(true), routes the manifest marks notices (POST /recovery/verify) ask for external delivery with x-seamless-auth-delivery-kinds, hand every item in deliveries to the deliver callback and strip deliveries from the answer. Without it the auth API sends the notices itself, since it counts a returned notice as the owner being told. A delivery of a kind this version does not know is logged and skipped instead of reaching the callback. The bundled manifest is synced from the auth API, adding the recovery, recovery code and staged policy routes, and ManifestRoute gains notices. Closes #12
Once the auth API returns deliveries it has opened the recovery request and counted the owner as notified, so answering 502 left the request running while the owner heard nothing. Every notice is still tried; one delivered is enough to answer normally. If none was delivered, the adapter cancels the request through POST /recovery/cancel with the token from a notice's cancel link, and answers 503 recovery_notice_failed. The link and token are never logged. Refs fells-code/seamless-auth-api#497
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The v0.20 work for the Rust adapter: the console proxy headers, placeholder secrets, recovery sessions and account recovery notices. One commit per item, plus a follow-up that cancels a recovery request when no notice was delivered.
#11: console proxy headers
console_routernow also forwards the API'sX-Frame-Options,Content-Security-PolicyandX-Content-Type-Options, so the console served on the app origin cannot be framed. Other upstream headers are still dropped.Placeholder secrets (fells-code/seamless-auth-server#231)
build()refusesdev-only-cookie-signing-key-replace-me,GRAB_FROM_SEAMLESS_AUTH_PORTAL_DEVand anything containingreplace-me(case-insensitive) for the cookie secret or the service secret, with the newBuildError::PlaceholderCookieSecret/PlaceholderServiceSecret.insecure_cookies(true), the adapter's local development mode, and a warning is logged.Recovery sessions (fells-code/seamless-auth-server#232)
Usergainsrecovery, read from the access token'srecovery: trueclaim (cookie and bearer).require_auth()answers a recovery session with 403{"error":"enrollment_required"}.require_auth().allow_recovery(true)lets one through.authenticate()returns the user withrecoveryset and leaves the check to the caller (documented).POST /webauthn/register/finishorPOST /totp/enroll/verify, the adapter refreshes in the same response, so the access cookie drops the claim. It goes through the shared refresher. If a silent refresh already rotated the cookie earlier in the request, it spends the token that refresh just issued, and the response carries one access and one refresh cookie. A failed refresh leaves the enrollment answer as it was. Bearer clients keep their own tokens and are documented to callPOST /auth/refreshafter enrolling.#12: account recovery delivery (fells-code/seamless-auth-api#500, @seamless-auth/types 0.31.0)
Deliverygainspurpose,notice,subject,textandcancel_url, plusis_account_recovery().Debugredactstextandcancel_url, since both carry the cancel credential.Builder::deliver_account_notices(bool), default false. Thedelivercallback receives every kind, so the adapter cannot tell for itself whether an app delivers notices. With the option on, routes the manifest marksnotices: true(todayPOST /recovery/verify) send external delivery with the delivery service token plusx-seamless-auth-delivery-kinds: account_notice_email,account_notice_sms. Every item indeliveriesgoes todeliver, anddeliveriesis stripped from the answer in both transports. Every notice is tried, and one delivered is enough to answer normally. If none was delivered, the API has already opened the request, so the adapter cancels it (POST /recovery/cancelwith{ "cancelToken" }taken from the fragment of a notice'scancelUrl, with the proxy service token and no credential) and answers 503recovery_notice_failed(fix(recovery): do not open an account recovery request unless the owner was notified seamless-auth-api#497). The cancel link and token are never logged.ManifestRoutegainsnotices(serde default; the manifest has nodeny_unknown_fields, and a test covers unknown fields). The bundledmanifest.jsonis synced from the API withscripts/sync-manifest.sh, which adds the/recovery/*,/recovery-codes*,/recovery/requests*and/system-config/policy*routes.recovery_notice_failedon/recovery/verify, 403step_up_requiredbodies on admin writes, and every new access, pre-auth and public recovery and policy route./recovery-codes/redeemand/recovery/completeissue session cookies.Checks
I did not run the conformance suite locally. CI runs it. The conformance secrets are not placeholders, so the new startup check does not affect them.
Closes #11
Closes #12