Verification flow
Emnet uses a redirect flow: you start a session, the user authenticates with the provider, and you exchange the returned code for verified claims.
The flow end to end
authorizeUrl and state.authorizeUrl.code and state.state with the stored one, then exchange the code. You receive a VerifiedIdentity.Step 1 — start a session
AuthorizeUrlResponse start = emnet.startPersonVerification();{
"authorizeUrl": "https://…/authorize?client_id=…&state=a7f3d21c9b0e",
"state": "a7f3d21c9b0e4f8a1c2e9b7d6a5c3e1f"
}authorizeUrl is single-use and time-limited. Redirect promptly rather than caching it, and never reuse one across users.
Step 2 — store the state, then redirect
state is the thread that ties the redirect back to the user who began it. Store it server-side against that user’s session and compare it when they return.
session.setAttribute("emnetState", start.state());
response.sendRedirect(start.authorizeUrl());Without it, an attacker can complete their own verification and hand the resulting callback URL to your user, attaching their verified identity to your user’s account. Reject any callback whose state is missing, unknown or does not match. Remove the stored value once used, so a callback cannot be replayed.
Step 5 — exchange the code
This call needs a secret key and must run on your server. A publishable key here gets 403.
if (!state.equals(session.getAttribute("emnetState"))) {
return badRequest(); // reject, do not continue
}
session.removeAttribute("emnetState");
VerifiedIdentity identity = emnet.completePersonVerification(code, state);The code is single-use. Exchanging it twice returns 400 — if you need the result again, read the session instead of re-exchanging.
Reading a session later
Session lookup returns status and metadata, never claims. It is for reconciliation — checking whether a verification you started ever completed.
VerificationSessionView view = emnet.getSession(4711L);
view.status(); // e.g. "COMPLETED"Sessions belong to the account that created them. Requesting another tenant’s session returns 404, not 403 — the API will not confirm that someone else’s session exists.
Cases to handle
| What happened | What you see | What to do |
|---|---|---|
| User abandons the flow | They never come back; no callback arrives | Nothing to clean up. The session expires on its own and is not billed. Let them start again. |
| User denies consent | Callback arrives without a usable code, or the exchange returns 400 | Treat as “not verified”, explain what consent is needed for, and offer a retry. |
| State does not match | Your own comparison fails | Reject the callback and log the event. Do not verify the user. |
| Code already used | 400 from the exchange | You are handling a duplicate callback. Read the session instead. |
| Provider unavailable | 503 with Retry-After | Back off and retry the start call. Do not treat as verification failure. |
| Rate limited | 429 with Retry-After | Back off — see rate limits. |
Practical notes
- Redirect URLs are registered. Emnet only redirects to URLs on your account, so an attacker cannot point the flow at their own site.
- Start on the server. You can start a verification from a browser with a publishable key, but the exchange always happens server-side.
- One session per attempt. If a user restarts, start a new session rather than reusing an old
authorizeUrl. - Don’t block your signup on it. Treat verification as a step that can be resumed — users lose network connections and close tabs mid-flow.