Building with the SDK
SDK changelog
What changed in each SDK release, newest first, and anything you need to do when upgrading.
Every release is backwards compatible unless an entry says otherwise under Action needed. New features are opt-in: upgrading doesn’t add anything to your screens that you didn’t ask for. When a fix changes how something looks or behaves, it’s listed under Fixes you will notice, so nothing changes without warning.
Unreleased
@zevauth/react, @zevauth/nextjs, @zevauth/js, @zevauth/backend, and
two new packages: @zevauth/ui and @zevauth/vue.
New
-
Python (
zevauthon PyPI, new). Session verification,get_authandrequire_auth(sync and async), the backend API client with sync and async clients and page iterators, webhooks and the session bridge, with integrations for FastAPI, Django and Flask. See Python. -
Go (
github.com/zevop/zevauth-go, new). Session verification,GetAuthandRequireAuth,net/httpmiddleware, the backend API client with a page iterator, webhooks and the session bridge, using the standard library only. See Go. -
Java and Spring Boot (
com.zevauth:zevauth-javaandcom.zevauth:zevauth-spring-boot-starter, new). Session verification, the backend API client, webhooks and the session bridge for any JVM server, with Jakarta Servlet adapters. The starter auto-configures everything fromzevauth.*properties and adds@RequireAuth, anAuthcontroller argument and Spring Security integration. See Java and Spring Boot. -
PHP and Laravel (
zevauth/zevauth-php, new). Session verification,getAuthandrequireAuth, the backend API client, webhooks and the session bridge for any PHP app, plus a Laravel integration: thezevauthmiddleware and guard, Blade directives, bridge routes and a webhook route helper. See PHP and Laravel. -
Ruby and Rails (
zevauthgem, new). Session verification,get_authandrequire_auth, the backend API client witheachpagination, webhooks and the session bridge for any Ruby app, plus Rack middleware and a Rails engine:require_zevauth!, view helpers, bridge routes andzevauth_webhook_event. See Ruby and Rails. -
Server SDK contract and conformance fixtures. Every ZevAuth server SDK now follows one written contract and runs one shared set of test tokens, webhook signatures and API errors, so every language behaves the same way. See Server SDKs.
-
Session bridge for server-rendered apps. A new
sessionBridge: { url }option in the browser SDK, the React provider,@zevauth/uiand Vue posts each new access token to your server, which keeps it in an HttpOnly cookie.@zevauth/backend/bridgeprovides the endpoint, the cookie reading and the handshake page. Off unless you set it. See Server-rendered apps. -
Webhook verification in Node.
verifyWebhookandconstructWebhookEventfrom@zevauth/backend(also@zevauth/backend/webhooks). -
users.resetMfa()andusers.iterate()in@zevauth/backend. Errors now carryrequestId, and 429 responses honourRetry-After. -
Stricter token checks in
@zevauth/backend/verify. Only RS256 is accepted, 5 seconds of clock difference are allowed, and refusals carry a code (token_expired,invalid_audience…) throughZevAuthVerifyError. -
Themes.
appearance.themetakes'soft','minimal','sharp','contrast'or'default'. You can override any value on top of a theme. See Themes. -
Design tokens.
appearance.variablessets colours, font, base size, radius, card shadow and card width. Every colour can take a{ light, dark }pair. See Variables. -
Per-element styling.
appearance.elementstakes a class name or a style object for any of 43 named parts. See Elements. -
Cascade layers.
appearance.cssLayerNameputs the component CSS in a layer, so your utility classes win without!important. -
appearanceon every component.<UserButton>,<UserProfile>,<OrganizationSwitcher>,<OrganizationProfile>and<SignInWithZevId>now take it, as<SignIn>and<SignUp>already did. -
Your own wording. A
localizationprop on the provider and on each component changes any label, button or message, or translates them all. Errors from the API can be replaced by code. See Customising the components. -
Server-rendered styles.
getComponentStyles()comes from@zevauth/react/stylesand@zevauth/nextjs/server. Use it to put the stylesheet in your server HTML without importing React. -
New exports.
Appearanceand its part types,themes,ThemeName,Localization,defaultLocalization.@zevauth/nextjsnow also re-exportsImageFieldanduseZevTheme. -
Organization and session methods in
@zevauth/js:organizations.create(),organizations.leave()andorganizations.delete().me.sessions(),me.revokeSession()andme.revokeOtherSessions().
Who can create or delete organizations is still controlled in the console.
-
New components.
<CreateOrganization>,<OrganizationList>(a “Choose an account” screen) and<UserAvatar>. See Components. -
Organization policy in the browser.
client.organizationSettingsreports whether end users may create organizations, whether slugs are on, and whether deleting from the app is allowed.<CreateOrganization>shows the slug field when your environment uses slugs, and the create and delete options hide themselves when the console turns them off. -
IP addresses in the device list are your choice. Under Authentication → Sessions in the console: hidden (the default), approximate (the network only), or full. The API applies it to
GET /v1/me/sessions, and<UserProfile showSessions />labels approximate addresses as such. -
New options on existing components. All are off by default, so your screens don’t change until you turn one on:
<UserProfile>:variant="sidebar", andshowSessionsto list the person’s signed-in devices with a way to sign them out.<OrganizationProfile>:variant="sidebar", plusshowLeaveandshowDelete. Delete asks for the name to be typed first.<OrganizationSwitcher>:createOrganizationModeadds “Create organization”.<UserButton>:userProfileModeadds “Manage account”, which opens the profile in a dialog or goes to your own page.
-
@zevauth/expo(new). Native sign-in for iOS and Android: the same hooks as@zevauth/react, native screens (sign-in, sign-up, two-step, account, profile with devices), the session in the Keychain or Keystore, and Sign in with ZevID through the system browser with PKCE. Themes, variables, elements and localization use the web’s vocabulary. See Expo and React Native. -
Native app support in
@zevauth/js. All additive; the web behaves as before:- an
asyncStorageoption for asynchronous stores; handleIncomingUrl()to finish a link the app was opened with;createZevIdAuthorizationUrl()for the system browser sign-in;revalidate()for when the app returns to the foreground.
@zevauth/reactadds a DOM-free@zevauth/react/headlessentry. - an
-
@zevauth/ui(new). Mount the components into any page, with no framework:mountSignIn(element)and friends, or a single script tag that setswindow.ZevAuthUI. See Any framework. -
@zevauth/vue(new). A Vue 3 plugin, composables with the same fields as the React hooks, the control components, and the UI components. Includes Nuxt usage. See Vue. -
Verifying tokens on any server.
@zevauth/backend/verifyexportsverifyZevAuthToken,getAuthandrequireAuthfor any server that uses the standardRequest. There are guides for React Router, TanStack Start and Astro. The main@zevauth/backendexport is unchanged. -
Two-step verification. People can protect their account with an authenticator app and recovery codes. It’s set per environment in the console: off, optional (the default) or required. Nothing changes for anyone until they set it up or you choose required. See Two-step verification.
<SignIn>and<SignUp>show the code step when a sign-in needs one, including after a magic link or ZevID.- Under required,
<SignIn>walks people through setup after they sign in. The new<TaskSetupMfa>catches anyone who arrives with setup still to do. <UserProfile>shows a two-step section under Security when your app requires it or the person has it.showMfacontrols it.- Options: remember devices for up to 90 days, trust ZevID’s own two-step, and choose whether organization admins can require it.
@zevauth/js:signIn.verifySecondFactor(),client.secondFactor,client.pendingTasks,client.mfaSettings,cancelSecondFactor()andclient.me.mfa.@zevauth/backend/verifyand@zevauth/nextjs/server:requireAuthrefuses sessions with setup still to do, and{ requireMfa: true }demands a second factor for one route.
-
Native apps. “Sign in with ZevID” from iOS and Android, following the OAuth standard for native apps:
- the sign-in can be bound to your app with PKCE and a
state; - a production sign-in returns only to a universal link or app link your domain has verified;
- register your apps under Project settings → Mobile apps, which generates the association files to publish and shows each app’s status;
- verified apps are named on the “Sign in with ZevID” consent screen with the device, such as “Acme on iPhone”.
See Native apps.
- the sign-in can be bound to your app with PKCE and a
-
PKCE for ZevID sign-in on the web.
client.signIn.withZevId({ pkce: true })binds the sign-in to the tab that started it and checks thestatethat comes back. Withoutpkce, nothing changes. -
ZevID sessions follow ZevID. A session that started with “Sign in with ZevID” ends when the person signs out of ZevID everywhere, changes their ZevID password or has their ZevID account closed, as it already did when they removed your app. Signing out of one ZevID session ends only the sessions made from it. Sessions are also checked against ZevID at least daily.
-
Trusting ZevID’s two-step works. With “Trust ZevID’s two-step” on, a ZevID sign-in that combined a password with a second step, within the last few minutes, skips your own code. An email code alone does not count.
It also needs a fresh ZevID sign-in after 90 days, or after 30 days unused. You can shorten both in the console. When that happens,
<SignIn>explains why the person was signed out.
Fixes you will notice
-
Next.js server verification is stricter.
@zevauth/nextjs/servernow uses the same verifier as every ZevAuth server library: RS256 only, five seconds of clock tolerance, and a cooldown on refetching keys for a token that names an unknown key. Valid tokens are accepted exactly as before. Errors fromverifyZevAuthTokenare now a typedZevAuthVerifyErrorwith acode(token_expired,invalid_audience, …), exported from@zevauth/nextjs/server. Code that only checked whether verification threw keeps working. -
Sign-up no longer stops after the confirmation code. In environments that ask for an email code before giving access,
<SignUp>confirmed the code and then stayed on the same screen with no session. It now signs the person in with the password they just chose, including the two-step step if they need one.
These fix behaviour that didn’t match the documentation. If you relied on the old behaviour, here’s what changes.
-
Sign in with ZevID now returns to the redirect you asked for, not always the first registered one. An app with several registered callbacks could land on the wrong one after a ZevID sign-in.
-
A failed ZevID sign-in returns your own
state. It used to carry an internal value instead, which your app couldn’t match. If you didn’t send astate, none comes back. -
accentColorset in code now paints. Before, anaccentColorinappearancechanged nothing and the console accent showed instead. If you set one and want to keep the console colour, remove it. -
The provider’s
appearancenow reaches every component.<UserButton>,<UserProfile>,<OrganizationSwitcher>,<OrganizationProfile>and<SignInWithZevId>used to ignore it. If you setappearanceon the provider, these now match your other components. -
signUpTitleandsignUpSubtitleset in code are now used. Before,<SignUp>always printed the console’s heading. -
No more double focus rings. If your site puts a global outline on
:focus-visible, it no longer draws a second ring around our fields and buttons. They keep their own focus ring. -
load()runs once even when called twice at the same time. A second call while the first was still running used to start a second load. That second load could try to spend a sign-in link or handoff code the first had already used, and the person saw a sign-in error. Concurrent calls now share one load. -
Avatar initials and profile spacing hold up against site styles. Some site stylesheets made the initials in
<UserButton>invisible, or put a large gap between<UserProfile>sections. Both are now protected from outside styles. -
Profile picture buttons size to their text. Replace and Remove in
<UserProfile>,<OrganizationProfile>and<ImageField>were stretching to full width against their intended design.
Changed under the hood
-
Sign-in methods now return a result.
signIn.withPassword(),verifyMagicLink()andverifyEmailCode()resolve to{ status: 'complete' }or{ status: 'needs_second_factor', … }instead of nothing. Code that ignores the result keeps working. Code that assigns these calls somewhere typed as() => Promise<void>may need its type widened toPromise<unknown>. That’s a type error, not a behaviour change. -
Font sizes now scale from a single
--zv-font-sizetoken. The sizes you see are unchanged. -
The members in
<OrganizationProfile>sit inside a newzv-member-listelement, and each row is azv-member. If you styled these rows by their inline styles, use the new classes.
Updated at, Sunday, November 1, 2026