Move users off your existing login
Moving to EdgeKit ID is three steps, one id mode each, and each site takes them on its own schedule. Your users keep one user id through all three, with the grants and memberships attached to it. EdgeKit makes each step for you as a deploy of your configuration; see Choose who signs users in.
| Step | Mode | Users sign in with | EdgeKit holds a session |
|---|---|---|---|
| 1 | external_only |
Your login | No |
| 2 | dual |
Your login | Yes, made from your login’s credential |
| 3 | edgekit_only |
EdgeKit ID | Yes |
Before step 1, connect your login as an identity provider. If your login signs tokens, have it put each site’s own
aud value, which EdgeKit gives you, in them. See Connect your existing login.
Step 1: read your login (external_only)
Section titled “Step 1: read your login (external_only)”Your login stays the only way in. On each request EdgeKit verifies your login’s credential and knows the user from
it; the first time it sees someone, it finds or creates their user. EdgeKit sign-in, /v1/id/user-details and
/v1/org/* answer 404.
Your rules see two kinds of access at such a site: the grants the user holds in EdgeKit, as grants.*, and what your
login says about them, as the external.* facts you map. The two are never merged, so a rule that should let your
login’s paying users in reads external.*. See
Claims from your login are facts, never grants.
Step 2: hand sessions to EdgeKit (dual)
Section titled “Step 2: hand sessions to EdgeKit (dual)”Your login still signs users in, and EdgeKit turns its credential into an EdgeKit session the first time it sees it. From then on the user reads with an EdgeKit session, even after your login’s credential expires.
Before this step:
- Move your rules off
external.*.external.*is empty at adualsite, and a deploy is refused while any feature reading it covers the site. Your paying users’ access must be grants in EdgeKit by then; see Subscriptions. - Give EdgeKit your login’s sign-out page. A deploy is refused without it. See Sign-out in dual.
EdgeKit sign-in stays closed at a dual site unless EdgeKit turns it on for that site. It is off by default because
your login may ask for more than an email, such as a second factor, and EdgeKit’s sign-in never does.
The exchange
Section titled “The exchange”GET /v1/id/get-session makes the exchange by itself. When the request carries no EdgeKit session, EdgeKit reads your
login’s cookie and:
- verifies the credential, and finds or creates the user, as in step 1;
- creates an EdgeKit session and answers with it, marked
"exchanged": trueon this one response; - expires your login’s cookies, under the names you gave EdgeKit, on the host the request reached. A cookie your
login set on a parent domain, such as
example.comfor a request towww.example.com, cannot be expired this way.
When there is no credential, or it does not verify, the answer is 200 with two nulls, as for anyone signed out,
and that browser is not tried again for 5 minutes. Retrying at once would cost your login a check per page view.
GET /v1/id/get-session answers no errors for a failed exchange. To see why one fails, call
POST /v1/id/session/exchange, which answers only in dual and 404 everywhere else. A browser sends it with the
cookie; it ignores the 5-minute pause.
| Status | Code | Message | Retry |
|---|---|---|---|
200 |
Each call creates a new session. | ||
401 |
external_credential_missing |
That credential was not accepted. |
No |
401 |
external_credential_expired |
That credential was not accepted. |
No: get a fresh credential |
401 |
external_credential_invalid |
That credential was not accepted. |
No |
503 |
identity_provider_unreachable |
The identity provider could not be reached. |
Yes, after Retry-After |
503 |
identity_provider_rate_limited |
The identity provider could not be reached. |
Yes, after Retry-After |
external_credential_invalid never says what was wrong with the credential, so that a forged one learns nothing.
Exchange from a native app
Section titled “Exchange from a native app”A native app has no cookie for EdgeKit to read, so it sends the credential in the body:
curl -i -X POST https://your-tenant-host/v1/id/session/exchange \ -H 'x-edgekit-site-id: site_example' \ -H 'content-type: application/json' \ -d '{"subject_token": "<your login credential>"}'The EdgeKit session token is in the set-auth-token response header; see
Native apps. subject_token takes up to 8192 characters, and
subject_token_type is accepted and optional. EdgeKit cannot delete the credential from your app’s storage: the app
discards it.
Sign-out in dual
Section titled “Sign-out in dual”The user holds two sessions, yours and EdgeKit’s, and neither ends the other. POST /v1/id/sign-out ends EdgeKit’s
and answers your sign-out page as logoutUrl. Send the browser there to end yours.
{ "success": true, "logoutUrl": "https://login.example.com/logout" }Step 3: EdgeKit ID only (edgekit_only)
Section titled “Step 3: EdgeKit ID only (edgekit_only)”EdgeKit signs users in, and your login’s credential is no longer read. EdgeKit sessions made in step 2 keep working. A user who did not come back during step 2 signs in with EdgeKit ID by email, and gets the user they already had, because that user holds their address.
Users change their own address with EdgeKit again; see Change the user’s email address.
Tell EdgeKit about changes in your login
Section titled “Tell EdgeKit about changes in your login”While your login owns your users, in external_only and dual, your server tells EdgeKit when it changes a person.
Four routes take the person’s sub in your login as subject. They need an API key, answer on your tenant host only,
never under /edgekit/, and a key pinned to any of your sites acts on any of your users.
| Route | Body | What EdgeKit does |
|---|---|---|
POST /v1/id/upstream/revoke-sessions |
subject, cause: lock or password_reset |
Ends every EdgeKit session the user holds. |
POST /v1/id/upstream/change-identifier |
subject, email, changedAt, optional emailVerified |
Moves the user’s address. Sessions stay. |
POST /v1/id/upstream/change-subject |
subject, newSubject |
Links the user to a new id in your login, such as after an account merge. |
POST /v1/id/upstream/erase |
subject |
Erases the user. See Erased users. |
const response = await fetch( 'https://your-tenant-host/v1/id/upstream/revoke-sessions', { method: 'POST', headers: { Authorization: `Bearer ${process.env.EDGEKIT_API_KEY}`, 'x-edgekit-site-id': 'site_example', 'content-type': 'application/json', }, body: JSON.stringify({ subject: 'user-6475b8', cause: 'lock' }), },);
const { userId, applied } = await response.json();Each answers 200 with { "success": true, "userId": "…", "applied": true }. applied: false means nothing changed,
for example no session to end, or an address change no newer than the last one, so retrying is safe.
- Revoke sessions reaches every browser within the delays in
How quickly an ended session stops working.
In
dual, a credential that is still valid makes a new EdgeKit session on its next request, so stop issuing it too. - Change identifier ignores a change whose
changedAtis not newer than the last one EdgeKit recorded, so an old retry cannot undo a newer change. WithoutemailVerified: truethe new address is stored unverified. It does not end sessions: send a revoke as well if the change was a takeover. - Change subject cannot be retried: afterwards the old subject names nobody.
| Status | Code | Message | Cause |
|---|---|---|---|
404 |
not_found |
No user is bound to that subject. |
EdgeKit has never seen that subject. |
409 |
conflict |
That address is already held by another user. |
Change identifier: details.collidingUserId names that user. |
409 |
conflict |
That subject is already bound to another user. |
Change subject: details.collidingUserId names that user. |
503 |
service_unavailable |
This tenant has no identity provider. |
Your organization has no identity provider connected. |
A missing, revoked or wrongly pinned key is refused as on every key route; see Issue and revoke API keys.