Skip to content
All articles
Engineering24 April 2026·7 min read

Getting somebody back to the page they actually wanted

A link from an email, a sign-in in the middle, and a landing page that is not where they were going. The fix is a redirect parameter, which is also a vulnerability.

Paycux engineering

Somebody clicks a link to a specific document inside your product. They are not signed in, so they are sent to authenticate, and after a redirect through their identity provider they land on a dashboard. The thing they were trying to open is now four clicks away, and they have already forgotten which document it was.

The remedy is to carry the intended destination through the authentication flow and return to it afterwards. It is a small feature that is quietly responsible for a large amount of perceived quality, and it is also the mechanism behind one of the most common vulnerabilities on the web, so it is worth building carefully rather than adding a return parameter and moving on.

Carry the destination, never the session

The value moving through the flow should be where the person wanted to go, and nothing else. A session identifier or a token in a URL is visible in browser history, in the referrer header sent to third parties, in server access logs, in any proxy along the way, and in the message when somebody pastes the link to a colleague. That is a credential distributed to everywhere a URL can end up.

Where a credential genuinely has to move — a genuine handoff between two domains you own — use a single-use code with a lifetime measured in seconds, exchanged immediately for a session on arrival and invalid thereafter. The exchange must be a POST from the receiving domain, so the code is spent by the server rather than by anything that merely saw the link.

A token in a URL is a credential you have copied into browser history, referrer headers and every access log on the path.

The redirect parameter is an open redirect until you constrain it

Whatever you name it, that parameter is attacker-controlled text that your application will navigate to after a successful sign-in. Unconstrained, it lends your domain's credibility to a phishing page: the link genuinely starts at your site, the sign-in is genuinely yours, and the landing page is not. It is also the standard way an authorisation code gets delivered somewhere it should not go.

Validate it as a relative path against a known pattern rather than parsing it as a URL and checking the host, because URL parsing has produced a long history of bypasses through backslashes, encoded characters, embedded credentials and protocol-relative forms. If the value does not begin with a single slash followed by a path you recognise, discard it and use the default. Where you must support several of your own hostnames, keep an explicit list; never accept a suffix match on your domain, since an attacker can register a domain that ends with your name.

  • Accept relative paths only, matched against an allowlist pattern
  • Reject anything with a scheme, a host, a backslash or a protocol-relative prefix
  • Where cross-domain is required, use an exact-match list of hosts, never a suffix check
  • Keep the destination server-side, keyed to the flow, if the value is long or structured
  • Re-check authorisation on arrival; passing through sign-in grants nothing by itself

Arriving somewhere you may not enter

The destination was chosen before anybody knew who the person was. After authentication they may lack access to it, or belong to a different organisation than the one that owns it, or be a member of several and need the right one selected first. Redirecting blindly produces a permission error immediately after a successful sign-in, which reads to the user as a broken product.

Handle it as a real state. If they cannot access the resource, say what it was and offer the route to request access. If the resource belongs to an organisation they are a member of but not currently in, switch context and continue rather than failing. That switch is exactly where a stale permission cache shows up, because the check runs against a membership that was resolved moments earlier under a different context.

Native applications and the handoff back

A link that should open in an installed application, an authentication that has to happen in a system browser, and a return to the application afterwards: the same problem with a less forgiving platform. A custom scheme can be claimed by another application on the device, so the return leg is not a trustworthy channel and must carry a single-use code bound to a value the application generated before it started.

The other half is the case where the application is not installed. That path must land somewhere useful in a browser rather than at an error, because it is the first experience for anybody following a shared link on a device they do not normally use. Both halves are ordinary work; they are just work that only surfaces when somebody tests the flow on a device that is not their own.

Everything here, already built

Sign-in, enterprise SSO, directory provisioning, roles and an audit trail behind one API. Start with the quickstart and have a working sign-in this afternoon.

Start selling to enterprise customers

Create an account, point sign-in at Paycux, and get back to the part of the product that is actually yours.