Repository navigation
Test auth and the OAuth loopback - #44
Merged
Merged
Conversation
Chunk 2. Adds src/auth.test.ts, 38 tests. One source change: export startCallbackServer (and its result type) so the loopback's state filtering can be exercised directly. The loopback server is driven for real — bind 127.0.0.1:0, send it an actual HTTP request — because that port is reachable by any local process or a drive-by page. A forged state gets a 400 and the server keeps listening, so a stray first hit can't abort a login in progress; the real redirect still lands afterwards. The full browser flow runs end to end too: registration, the authorize URL, a real callback, then the token exchange. PKCE S256, the state, the RFC 8707 resource indicator and the loopback redirect_uri are all asserted on both requests. Also covers decodeTokenClaims across every token shape, the strict --api-key-oauth refusal, and the /me path for an opaque key: Basic header, host from the realm prefix, an -eu1 org overriding the region, and distinct messages for 401/403, other statuses, a missing orgId and an unreachable host. Two tests record current behavior rather than endorse it: authenticate compares state before it reads `error`, so an error redirect that omits the state reports a mismatch instead of the server's reason.
This was referenced Sep 24, 2026
Merged
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.
Chunk 2 of the test plan.
src/auth.test.ts, 38 tests, plus one source change.Source change
startCallbackServerandCallbackResultare now exported. The state filtering inside that server is a security boundary and is worth exercising directly rather than only through a fullauthenticate()run. Nothing else moved.The loopback server, driven for real
Bind
127.0.0.1:0, send it actual HTTP requests. That port is reachable by any local process or a drive-by web page, so the interesting cases aren't the happy path:/callback404s.error_descriptioninto the message.The browser flow, end to end
authenticate()runs for real against its own loopback server: dynamic client registration → authorize URL → an actual HTTP callback → token exchange. Asserted on both requests: PKCES256with a 43-char challenge and a matching verifier, the state, the RFC 8707 resource indicator, and theredirect_uri. Plus registration failure, exchange failure, a token with no org, the refresh token, andopenBrowser: falseprinting the link instead of callingopen.The rest
decodeTokenClaimsacross every shape: realm prefix,-eu1org suffix inference, no region to infer, too few segments, non-JSON payload.--api-key-oauthrefuses a non-OAuth value rather than silently falling through to the/mepath — that's what--api-keyis for./mepath for an opaque key:Basicheader, host chosen from thena1./eu1.prefix, an-eu1org id overriding the region, and distinct messages for 401/403 vs other statuses vs a missingorgIdvs an unreachable host.One rough edge, recorded not fixed
authenticate()comparescallback.statebefore it readscallback.error. So an error redirect that omits the state surfacesOAuth state mismatch — aborting login for safetyinstead of the server's actual reason. Real OAuth servers echo state on error redirects, so this is an unlikely path, and reordering it is a behavior change rather than a test. There are two tests pinning both branches; happy to flip the order in a follow-up if you'd rather.Verification
38 tests passing (91 across the suite),
typecheckclean. Mutation-checked the two load-bearing assertions — disabling the state guard and downgrading PKCE toplain— and confirmed exactly the relevant tests fail, then reverted.Note
Low Risk
Production change is export-only with no auth logic edits; risk is limited to test maintenance and documenting existing OAuth edge-case behavior.
Overview
Adds
src/auth.test.ts(~38 tests) covering authentication end-to-end: token claim parsing, the OAuth loopback callback server, supplied credentials, opaque API key resolution via/me, and the full browser OAuth flow (PKCE, dynamic registration, token exchange, failure paths).The only production tweak is exporting
startCallbackServerandCallbackResultfromauth.tsso tests can hit the loopback state filtering directly—especially that forged or missing state returns 400 without consuming the one-shot callback, while valid success/error redirects still complete login.Tests also lock in
--api-key-oauthrejecting non-OAuth values (no silent fallthrough to/me) and record current behavior when an OAuth error redirect omits state (state mismatch vs server error message).Reviewed by Cursor Bugbot for commit b3ff419. Bugbot is set up for automated code reviews on this repo. Configure here.