Skip to content

fix: 12 logical issues across HTTP handlers and GraphQL modules#602

Merged
lakhansamani merged 6 commits intomainfrom
fix/http-handler-logical-issues
Apr 9, 2026
Merged

fix: 12 logical issues across HTTP handlers and GraphQL modules#602
lakhansamani merged 6 commits intomainfrom
fix/http-handler-logical-issues

Conversation

@lakhansamani
Copy link
Copy Markdown
Contributor

@lakhansamani lakhansamani commented Apr 9, 2026

Summary

Systematic code review of all HTTP handlers and GraphQL modules uncovered 12 logical issues ranging from critical (broken hybrid flow code exchange) to low (spec-compliance nits). All fixed with tests.

Critical / High

  • 1 Hybrid flow stored raw nonce (FingerPrint) instead of AES-encrypted session (FingerPrintHash) in authorize.go — code exchange at /oauth/token always failed for hybrid flows (OIDC Core §3.3)
  • 2 Scope override in signup.go and session.go checked len(scope) (always 3) instead of len(params.Scope) — empty scope list would strip all scopes from tokens
  • 3 Null pointer dereference in verify_otp.go when storage returns (nil, nil) — condition otp == nil && err != nil misses the (nil, nil) case

Medium

  • 4 resend_otp.go used unsanitized params.Email for OTP lookup instead of the trimmed/lowercased email variable
  • 5 Scope parsing in oauth_callback.go: space-split silently overwrote comma-split; also handled single-value scopes (RFC 6749 §3.3)
  • 7 Phone number uniqueness check in admin _update_user was commented out (TODO) — admins could assign duplicate phones
  • 8 revoke_refresh_token.go used plain != for token comparison instead of subtle.ConstantTimeCompare (RFC 7009 §2.1)
  • 10 Unsafe type assertions across oauth_callback.go social provider functions — panics if API response shape changes
  • 11 json.Unmarshal errors silently dropped in 5+ locations in oauth_callback.go

Low

  • 6 Vestigial @@ separator in token.go nonce for refresh_token grants (code is empty)
  • 9 Wrong error message in resend_otp.go SMS branch ("email service not enabled" → "SMS service not enabled") + clarifying comment on confusing condition
  • 12 Logout handler returned JSON error for invalid post_logout_redirect_uri instead of silently ignoring per OIDC spec (RP-Initiated Logout §2)

Test plan

  • New integration test: hybrid flow full code exchange (authorize → extract code → /oauth/token)
  • New tests: signup/session with empty scope list retains defaults
  • New test: verify_otp with no OTP record returns error (not panic)
  • New tests: refresh token nonce has no trailing @@, revoke with wrong token returns 200
  • New tests: resend_otp sanitized email lookup, SMS error message
  • New unit tests: scope parsing (comma, space, single value, mixed)
  • New test: admin update_user rejects duplicate phone number
  • New test: logout with invalid redirect_uri does not return JSON error
  • Full suite: 575/575 tests passing (SQLite), zero regressions

…code exchange

The hybrid flow path in authorize.go stored authToken.FingerPrint (the
raw nonce) instead of authToken.FingerPrintHash (the AES-encrypted
session data) when stashing the code for /oauth/token exchange.

When /oauth/token later calls ValidateBrowserSession on sessionDataSplit[1],
it tries to AES-decrypt the value. Since the nonce is not AES-encrypted,
this always fails for hybrid flow codes.

The other two code paths (code flow at line 520 and oauth_callback at
line 331) correctly store AES-encrypted session values.
…ssion

The scope override condition in signup.go and session.go checked
len(scope) (the default list, always 3) instead of len(params.Scope),
making it impossible to pass an empty scope list and retain defaults.
Fixed to match the correct pattern already used in login.go.

Added integration tests verifying that an empty Scope slice falls back
to the default scopes (openid, email, profile).
…time token comparison

- verify_otp.go: change `otp == nil && err != nil` to `otp == nil` to
  prevent nil pointer dereference when storage returns (nil, nil)
- token.go: only append "@@" + code to nonce when code is non-empty,
  avoiding vestigial "uuid@@" in refresh_token grant flow
- revoke_refresh_token.go: use crypto/subtle.ConstantTimeCompare for
  token comparison to prevent timing oracle attacks (RFC 7009)
- add integration tests for all three fixes
…ong error message

- use sanitized email/phoneNumber locals instead of raw params.Email
  and params.PhoneNumber when calling GetOTPByEmail/GetOTPByPhoneNumber
- fix SMS-disabled error message from "email service not enabled" to
  "SMS service not enabled"
- add clarifying comment on the MFA/verified guard condition
- add integration tests for sanitized-email resend and SMS error message
…ing in oauth_callback

- Fix scope parsing to use else-if so comma-delimited scopes aren't
  silently overwritten by space-split; handle single-value scopes
- Convert all unsafe type assertions to safe form with ok-checking
  across Facebook, LinkedIn, Twitter, Discord, and Roblox processors
- Add error checking for all json.Unmarshal calls that were silently
  dropping parse failures (GitHub, Facebook, LinkedIn, Twitter, Roblox)
- Extract parseScopes helper with unit tests covering comma, space,
  single-value, and mixed-delimiter inputs
…irect handling

- Remove stale TODO comment in update_user.go; phone uniqueness check
  already exists at lines 198-214 with proper length validation
- Change logout handler to silently ignore invalid post_logout_redirect_uri
  per OIDC RP-Initiated Logout §2 instead of returning a JSON 400 error
- Add integration test for duplicate phone number rejection via admin
  _update_user mutation
- Add integration test verifying invalid redirect URI no longer produces
  a JSON error response
@lakhansamani lakhansamani merged commit 0ccc1c5 into main Apr 9, 2026
@lakhansamani lakhansamani deleted the fix/http-handler-logical-issues branch April 9, 2026 08:33
lakhansamani added a commit that referenced this pull request Apr 11, 2026
Take main's PKCE refactoring and authorize.go restructuring from #603,
re-apply security audit fixes (configurable SameSite, client_id log removal,
atomic consumeAuthorizeState, cache TTL reduction).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant