Skip to content

fix: strip hash fragment when comparing redirect vs current URL (closes #2143)#2220

Open
FabianGosebrink wants to merge 2 commits into
mainfrom
fix/url-comparison-strip-fragment
Open

fix: strip hash fragment when comparing redirect vs current URL (closes #2143)#2220
FabianGosebrink wants to merge 2 commits into
mainfrom
fix/url-comparison-strip-fragment

Conversation

@FabianGosebrink

Copy link
Copy Markdown
Collaborator

Summary

UrlService.getUrlWithoutQueryParameters now also clears u.hash. That's the entire production change — 1 line + a comment. Closes #2143 (Facebook #_=_ callback stuck) and fixes a related implicit-flow regression two commenters reported on the same issue.

Two commits so the diff is reviewable:

  1. chore: normalize line endings on url.service.spec.ts — the spec file was checked in with mixed CRLF/CR/LF (git treated it as -text/binary). Re-encode to LF to match the rest of the repo. No semantic change.
  2. fix: strip hash fragment when comparing redirect vs current URL — the actual fix + 3 new tests.

The bug

With checkRedirectUrlWhenCheckingIfIsCallback: true, isCallbackFromSts compared currentUrl and redirectUrl after stripping the query string. The hash fragment was kept. Two providers were silently broken:

  • Facebook appends "#_=_" to OAuth redirects (known behavior). Result: https://app.com/cb?code=…#_=_ was rejected because https://app.com/cb#_=_https://app.com/cb.
  • Implicit flow puts the auth response in the fragment by design (#access_token=…&state=…). Same root cause: the fragment made the URL strings unequal.

Both reported in #2143 — original author for Facebook, two follow-up commenters for implicit flow and a regression on the v17→v20 upgrade.

The fix

 keys.forEach((key) => {
   u.searchParams.delete(key);
 });

+// Also drop the hash fragment. Some identity providers (e.g. Facebook)
+// append "#_=_" to their redirect URL, and implicit flow puts the auth
+// response in the fragment by design. Either way, the fragment is not
+// part of the configured redirect URL and must not factor into the
+// base-URL comparison done by isCallbackFromSts.
+// https://github.com/damienbod/angular-auth-oidc-client/issues/2143
+u.hash = '';

 return u;

The companion check (the configured redirect's query parameters must all be present on the current URL) is unchanged — it still defends against partial-match callback URLs.

Does it change behaviour?

Yes — but only in the direction the bug report demands.

  • isCallbackFromSts may now return true in cases where it previously (incorrectly) returned false: specifically, when currentUrl carries a hash fragment that the configured redirectUrl doesn't have. That covers the Facebook + implicit-flow cases above.
  • It does not turn any previously-true result into false. Nothing that worked before stops working.
  • The query-parameter presence check is untouched, so a current URL missing the redirect URL's required query params still fails as before.

The only edge case would be a user who configures redirectUrl with a hash fragment (e.g. https://app.com/cb#foo) and expects the fragment to be enforced. That's against the OAuth spec (RFC 6749 §3.1.2: redirect URI MUST NOT include a fragment) and would have been broken in other ways even before this PR.

Internal helper note: getUrlWithoutQueryParameters is now slightly misnamed (it also strips the fragment). The method isn't exported via the lib's index.ts so the rename can happen separately if you want. Left as-is here to keep the fix minimal.

Test plan

  • 3 new tests, all failed before the fix:
    • helper: getUrlWithoutQueryParameters also strips the hash
    • isCallbackFromSts: Facebook #_=_ regression
    • isCallbackFromSts: implicit-flow fragment
  • Full library test suite passes (101/101 in this spec; full suite green)
  • npm run lint-lib clean

🤖 Generated with Claude Code

The file was checked in with mixed CRLF/CR/LF line endings, which
git's auto-detection treated as binary (-text). Re-encode to LF to
match the rest of the repo (core.autocrlf = input). No semantic
changes — only line-ending bytes differ.

Committed separately so the bug-fix in the next commit shows a
clean diff.
Issue #2143: Facebook appends "#_=_" to OAuth redirect URLs. With
`checkRedirectUrlWhenCheckingIfIsCallback: true`, the trailing
fragment made `currentUrl != redirectUrl` after stripping the query
string, so `isCallbackFromSts` returned false. The page got stuck
on the callback URL because the library no longer recognised it as
an STS response.

The same root cause breaks implicit flow: the IdP returns the auth
response in the URL fragment by design (`#access_token=...&state=...`),
which the comparison treated as making the URLs unequal.

Fix: `getUrlWithoutQueryParameters` now also clears the fragment, so
the base-URL comparison only considers scheme/host/path. The query-
params-must-be-present-in-current-url check below is unchanged and
continues to enforce that the redirect URL's own query parameters
were preserved.

Adds tests for:
- the helper: hash is stripped along with query
- isCallbackFromSts: Facebook's "#_=_" trailing fragment
- isCallbackFromSts: implicit flow's response fragment

Full lib test suite passes; lint clean.

Fixes #2143
@damienbod

Copy link
Copy Markdown
Owner

This looks like a previous PR already in the repo. I need to verify, if the causes new bugs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Facebook appending #_=_ to redirected url

2 participants