Impersonation token via URL fragment
Impersonation token via URL fragment
HAPI Elements can now run an impersonation session driven by a token placed in the page URL fragment. This is useful for support and troubleshooting, where you want Elements to act on behalf of a specific user for a single browser session without changing the token your page normally configures.
How it works
Append the impersonation JWT to the URL fragment of the page that embeds Elements:
https://your-ats.example.com/careers#token=<JWT>When the page loads, Elements reads the fragment and, only when the token's
payload contains a non-empty impersonated_by value and the token has not
expired, uses it as the client token for every HAPI request in that session.
A regular token in the fragment that is not an impersonation token is ignored,
so #token= cannot accidentally replace your configured token.
Reading the fragment has to happen in the browser, because browsers never send the fragment part of a URL to a server. The token itself is then used exactly like a client token you configure yourself: it is sent to Elements and to the Hiring API to authenticate the session.
Use the fragment, not a query parameter
It has to be #token=. A ?token= query parameter is ignored, and building
your impersonation links that way instead is a meaningful downgrade in safety
rather than a matter of taste.
Browsers send the query string to the server as part of the request; they never
send the fragment. So ?token=<JWT> would put a credential for a real user
account into the request line of your own page load, and from there into your
web server access logs, load balancer and CDN logs, APM or error-tracking
breadcrumbs, and anything else in your request-logging path. Those are typically
retained for months and often forwarded to third parties, so exposure there is
very difficult to undo after the fact. A query string can also travel in the
Referer header of subsequent requests, which a fragment never does.
Two things worth carrying into your own integration:
- Do not rewrite impersonation links to use a query parameter.
- Do not log full page URLs for pages that may carry one — for the short moment before Elements removes it, the token is still in the address bar.
The token does not stay in the URL
As soon as Elements has read it, the token is moved out of the URL into the
tab's sessionStorage and the #token= entry is removed from the address bar
(other fragment values are kept). An impersonation token is a credential for the
account it belongs to, and a URL is easy to copy into a ticket, a chat message,
or a screenshot without noticing it is in there.
What this means in practice:
- Reloading the page keeps the session. The token is remembered for the tab.
- The session is per tab. Opening the same page in a new tab, or in another browser, is an ordinary session on your configured token.
- Closing the tab ends the session. A fresh impersonation link is needed to start another one.
- If the browser has storage disabled (private browsing with cookies blocked), the token stays in the fragment instead, because there it is the only thing that can survive a reload.
If the token is refused — expired, or not accepted for this environment —
Elements falls back to your configured client token on the next load rather than
retrying it. That check is part of validating the client token on load, so it
applies to the default setup and not to integrations running with
useJWTAuthHeaders: false, which pass no client token to fall back to.
A load that fails for some other reason keeps the session instead, so a retry resumes it: if the API could not be reached, the token was never refused and dropping it would end the session over a temporary problem.
Indicator and exiting
While an impersonation session is active, a banner is shown at the top of the page identifying who is being impersonated, with an Exit impersonation action. Exiting forgets the token and reloads the page, so Elements re-initializes with your default token.
The banner names the impersonated user by their customer id, read from the ATS user behind the token. Until that resolves it reads "You are impersonating another user." instead.
It is fixed to the top of the viewport, so your page's <body> gains
padding-top for its height while it is shown and your content is not covered.
That offset follows the banner if its height changes, for example when the text
wraps on a narrow viewport. A fixed header of your own needs its own top offset
while window.hapi.auth.isImpersonating is true; Elements' debug panel is
moved for you.
You can also drive this from the SDK on window.hapi.auth:
// True when the active token is an impersonation token
window.hapi.auth.isImpersonating
// Who started the impersonation, from the token's `impersonated_by`
// claim (undefined when not impersonating). The initiator — not the
// user being impersonated, who is the one the banner names.
window.hapi.auth.impersonatedBy
// Exit impersonation: forgets the token and reloads with the default
// token. Does nothing when there is no impersonation session to end.
window.hapi.auth.clearImpersonation()While impersonating, the automatic JWT refresh is paused, so the impersonation token is used exactly as provided for the session — refreshing would replace it with an ordinary token and end the session without saying so.
An explicit window.hapiApi.refreshJWTToken() still works as documented. Because
it replaces the token, it ends the impersonation session: the banner comes
down with it, and the remembered token is discarded, so a later reload continues
on your configured token rather than reopening the session.
Backwards compatibility
- The behavior only activates for unexpired tokens whose payload contains a
non-empty
impersonated_byvalue; all existing sessions are unchanged. isImpersonating,impersonatedBy, andclearImpersonation()are new additive members ofwindow.hapi.auth— nothing was removed or renamed.window.hapiApi.refreshJWTToken()keeps its existing behavior for every session, impersonated or not. Only the automatic background refresh changes.- No HTML ids, CSS classes, events, or existing translation keys were removed.
I18n
The following i18n translations have been added (used by the impersonation banner). The banner follows your configured language, and you can override any of these strings by key like any other translation:
| Key | "en" value | "de" value | "nl" value | "fr" value | "es" value | "it" value |
|---|---|---|---|---|---|---|
| auth.impersonation.banner | You are impersonating {user}. | Sie agieren im Namen von {user}. | Je handelt namens {user}. | Vous incarnez {user}. | Estás suplantando a {user}. | Stai impersonando {user}. |
| auth.impersonation.banner.unknown-user | You are impersonating another user. | Sie agieren im Namen eines anderen Benutzers. | Je handelt namens een andere gebruiker. | Vous incarnez un autre utilisateur. | Estás suplantando a otro usuario. | Stai impersonando un altro utente. |
| auth.impersonation.clear | Exit impersonation | Identitätswechsel beenden | Imitatie beëindigen | Quitter l'usurpation d'identité | Salir de la suplantación | Esci dall'impersonificazione |