|
| 1 | +# Redirects in Login App |
| 2 | + |
| 3 | +This document explains how post-authentication redirect is determined on success and failure, and explains various redirect flows |
| 4 | + |
| 5 | +## Reference: |
| 6 | + |
| 7 | +- https://docs.pingidentity.com/pingoneaic/am-authentication/redirection-url-precedence.html |
| 8 | +- https://github.com/ping-rocks/platform-ui/blob/master/packages/platform-login/src/views/Login/index.vue |
| 9 | +- https://github.com/ping-rocks/platform-ui/blob/master/packages/platform-shared/src/mixins/LoginMixin/index.vue |
| 10 | + |
| 11 | +## Functionality |
| 12 | + |
| 13 | +- Redirect users to the correct target after login success or failure |
| 14 | +- Prevent open-redirect issues by validating URL against `validateGoto` endpoint |
| 15 | +- Handle common edge cases: default console paths, SAML endpoints, admin vs end user redirects |
| 16 | + |
| 17 | +## Redirect inputs |
| 18 | + |
| 19 | +Redirect URLs can come from multiple places: |
| 20 | + |
| 21 | +- Query parameters: |
| 22 | + - `goto` (success) |
| 23 | + - `gotoOnFail` (failure) |
| 24 | +- Journey outcome: |
| 25 | + - Success URL from the journey step (for example `step.getSuccessUrl()`) |
| 26 | + - Failure URL from the journey payload (for example `step.payload.detail.failureUrl`) |
| 27 | +- AM defaults (applied by AM when validating): |
| 28 | + - User profile success/failure URL attributes |
| 29 | + - Realm default success/failure login URL attributes |
| 30 | + |
| 31 | +## Success and Failure redirection flow (`goto` and `gotoOnFail`) |
| 32 | + |
| 33 | +### 1) Initial request (client) |
| 34 | + |
| 35 | +- When the authentication journey completes on the client, a hidden form is submitted to the server to initiate the redirect flow. This form contains the necessary redirect information (such as success/failure state and URLs). |
| 36 | + |
| 37 | +### 2) Storing redirect params (server) |
| 38 | + |
| 39 | +- Read `goto` / `gotoOnFail` from the incoming URL or from the submitted form. |
| 40 | +- Store values in a short-lived **HTTP-only** cookie. |
| 41 | + |
| 42 | +### 3) Redirect function performs the final redirect (server) |
| 43 | + |
| 44 | +1. Read and parse the HTTP-only cookie (`goto` / `gotoOnFail`). This cookie is cleared after it’s read to avoid stale redirects. |
| 45 | +2. Select a possible `gotoUrl`: |
| 46 | + - If `isGotoOnFail=true`: prefer cookie `gotoOnFail`. |
| 47 | + - If `isGotoOnFail=false`: prefer cookie `goto`, otherwise use the client-provided URL (typically from the journey success step). |
| 48 | +3. Call `validateGoto(authorization, gotoUrl)` in AM. AM may return a `successUrl` even when the input is invalid. It will fall back to the default success URL. |
| 49 | +4. If there is no usable `gotoUrl`, compute a default redirect, which redirects to either admin or end user. |
| 50 | +5. Final fallback: |
| 51 | + |
| 52 | +- If all redirect logic fails (no valid URL can be determined), the server will redirect to static fallback files: |
| 53 | + - `/success-redirect` for success cases |
| 54 | + - `/failure-redirect` for failure cases |
| 55 | +- These files provide a guaranteed fallback destination for both success and failure scenarios. |
| 56 | + |
| 57 | +## Other flows |
| 58 | + |
| 59 | +### Default path |
| 60 | + |
| 61 | +- detect destinations whose last path segment is `console` (for example `/am/console` or `/auth/console`). |
| 62 | +- If `validateGoto` return a non-console URL, use it. |
| 63 | +- If `validateGoto` return a console URL: |
| 64 | + - Failure flow: return an empty redirect so the client can redirect to the journey `failureUrl` or the global fallback. |
| 65 | + - Success flow: if the client provided a non-console URL from the journey, prefer that. |
| 66 | + |
| 67 | +### SAML URLs |
| 68 | + |
| 69 | +If `validateGoto` falls back to a console URL but the original `goto` looks like SAML, return the original `goto`. |
| 70 | +For example, when `validateGoto` endpoint returns '/am/console' as successUrl and the corresponding `goto` query param is 'https://default.iam.example.com/am/Consumer/metaAlias/avsp', SAML condition becomes true and the `goto` URL is returned |
| 71 | + |
| 72 | +### Admin vs end user default |
| 73 | + |
| 74 | +When there is no usable `goto` (or redirect selection must fall back), the server computes a default destination: |
| 75 | + |
| 76 | +- Fetch the user record and determine whether the user is an admin (based on roles/groups). |
| 77 | +- Admin users go to an admin landing page; non-admin users go to an end user landing page. |
| 78 | + |
| 79 | +### suspendedIdParam |
| 80 | + |
| 81 | +Some journeys like email verification / magic links / text and sms temporarily **suspend** the authentication session. |
| 82 | + |
| 83 | +In these flows: |
| 84 | + |
| 85 | +1. Customer app is where the flow begins. |
| 86 | +2. Customer is redirected to authorization server and then to the Login App for authentication. |
| 87 | +3. Login app passes the `goto` and `gotoOnFail` params to AM and AM links this parameter with the active auth session in memory. This happens through the SDK options (`StepOptions.query.goto` and `StepOptions.query.gotoOnFail`). |
| 88 | +4. AM stores all of these relevant state params in the `suspendedId`, so the magic link sent to the user contains the `goto` param within this `suspendedId` in the URL. |
| 89 | +5. AM then restores the goto URL, and AM is able to send the user to this URL upon completion of the journey (turned into the successUrl). |
0 commit comments