Delegated access to Zev products
High-risk permissions
Permissions that are hard to undo, such as deleting a service. How users grant them, how long they last, and how to ask a user to confirm again.
Some permissions are hard to undo, for example deleting a service. A Zev product marks those permissions as high risk. Your app can only request one after ZevID approves it for your app on that product. Approval is per app and per product, and a product marking a permission high risk never approves it for anyone.
What the user sees
When your authorize request includes a high-risk permission:
- They confirm it is them. If the user has not signed in to ZevID in the last 5 minutes, ZevID asks for their password first. If they use two-factor authentication, it also asks for their authenticator code.
- The permission is labelled. It shows a plain “High risk” label and one sentence explaining why.
- It starts unticked. The user has to tick it on purpose.
The user can allow the connection without ticking it. The rest of the connection works as normal.
The confirmation window
A high-risk permission only works for a limited time after the user confirms it:
- 30 days by default.
- A product can set its own window, from 1 to 90 days.
- ZevID can set a shorter window for a particular app.
When the window ends, new tokens stop carrying the permission. The rest of
the connection keeps working. Access tokens issued before the end also
stop working for high-risk routes, because the product checks hr_exp.
Token response fields
The token response carries three fields about high-risk permissions:
| Field | Value |
|---|---|
auth_strength | user_consent when the token carries only standard permissions. user_consent+recent_auth when it carries at least one active high-risk permission. |
hr_exp | The earliest end of an active high-risk permission, in epoch seconds. null when none is active. |
high_risk | Every high-risk permission on the connection: [{ scope, confirmed_at, expires_at, active }]. active: false means its window ended. |
{
"scope": "zevcloud.deploy zevcloud.services.delete",
"auth_strength": "user_consent+recent_auth",
"hr_exp": 1763200000,
"high_risk": [
{
"scope": "zevcloud.services.delete",
"confirmed_at": "2026-10-20T08:00:00.000Z",
"expires_at": "2026-11-19T08:00:00.000Z",
"active": true
}
]
}
The scope names here are examples. Use the ones your product publishes; see Scopes by product.
Asking the user to confirm again
Send the user through authorize with
prompt=reconfirm. scope is optional; when you send it, it must be a
subset of the connection’s high-risk permissions. ZevID shows a short screen,
the user confirms it is them, and a fresh window starts. You then exchange the
code as usual. The connection’s targets and other permissions do not change.
https://api.zevauth.net/v1/partner/delegated/authorize
?publishable_key=pk_live_...
&resource=zevcloud
&prompt=reconfirm
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fzev%2Fcallback
&state=...
&code_challenge=...
&code_challenge_method=S256
The user can also confirm again from Apps and websites in their ZevID account.
Send the user through reconfirm when:
- A refresh returns
invalid_grantwithreason: "high_risk_expired". The connection has nothing usable left except ended high-risk permissions. - The product answers a call with
403 high_risk_confirmation_required. high_riskshows the permission withactive: falseand the user wants to do something that needs it.
When the user did not grant it
Design for a connection without the high-risk permission:
- Hide or disable the features that need it, and say why.
- Offer a button that sends the user through authorize again with the same scopes. An ended or never-granted high-risk permission comes back as an opt-in choice.
- Do not send the user through consent in a loop. Ask when they try to use the feature.
Your users get an email from ZevID 3 days before a window ends, but only if your app used the permission in the last 30 days.
Updated at, Wednesday, October 21, 2026