Persist OAuth tokens, refresh safely, and keep framework auth clients supplied with fresh ID tokens.
OAuth tokens expire on a short clock. That is separate from how long a user should stay signed in. When your app requests offline_access, Ave issues a refresh token so your app can rotate tokens without sending the user through consent again.AveSession gives you one supported lifecycle for that work: persist the token bundle and any encryption keys, refresh before expiry, collapse duplicate refresh calls, broadcast changes across tabs, and save rotated refresh tokens atomically.
Disconnecting an app in Ave invalidates its refresh tokens and access to Ave APIs for the selected identity, and deletes its encryption keys for that identity. Handle a definitive invalid_grant by clearing the app session and starting sign-in again. Reconnecting requires consent, does not reactivate old tokens, and provisions new encryption keys.An ID token already accepted by another service remains subject to that service’s session policy and the token’s expiry. Signing out locally only clears the local session.
completeOAuthCallback runs finishPkceLogin and setTokensFromResponse together. Use it on your OAuth callback route, then call hydrate() during app startup.If the redirect carries encryption keys in its fragment, finishPkceLogin merges them into the token response and removes them from the URL. session.getAppKeyBase64(), getAppPublicKeyBase64(), and getAppPrivateKeyBase64() return the stored keys after hydrate().
Set devtools: true only in development. It exposes window.__aveSessionDev with state, expiry helpers, and lastRefreshError.
getValidIdToken() waits for proactive refresh when the JWT is near expiry. createLocalStorageAdapter() keeps the refresh token and any encryption keys in localStorage. For stricter setups, use createMemoryStorage(), your own AveSessionStorage, or a backend-for-frontend with customRefresh.
import { ConvexReactClient } from "convex/react";import { wireAveSessionToConvex } from "@ave-id/sdk/convex";const convex = new ConvexReactClient(CONVEX_URL);await session.hydrate();wireAveSessionToConvex(convex, session);
Call session.setTokensFromResponse after login. wireAveSessionToConvex passes a function that calls getValidIdToken() so Convex always receives a valid token.
Native Expo has no Web Crypto for PKCE SHA-256. Configure expo-crypto once with configureAveSdkForExpo from @ave-id/sdk/expo-session, then use AveSession with createSecureStoreAdapter and completeExpoOAuthCallback. See Expo with AuthSession.
import * as ExpoCrypto from "expo-crypto";import * as SecureStore from "expo-secure-store";import * as WebBrowser from "expo-web-browser";import { AveSession, completeExpoOAuthCallback, configureAveSdkForExpo, createSecureStoreAdapter, initExpoOAuthBrowserSession, onExpoAppForegroundRefresh, warmUpExpoAuthBrowser,} from "@ave-id/sdk/expo-session";import { AppState } from "react-native";initExpoOAuthBrowserSession(WebBrowser);configureAveSdkForExpo(ExpoCrypto);const session = new AveSession({ oauth: { clientId: "...", redirectUri: "myapp://callback" }, storage: createSecureStoreAdapter(SecureStore), crossTabSync: false,});onExpoAppForegroundRefresh(AppState, session);// Optional: in your login screen component// useEffect(() => warmUpExpoAuthBrowser(WebBrowser), []);
Pass customRefresh in AveSession options to POST to your own /api/session/refresh endpoint. That endpoint can read an HttpOnly cookie and return TokenResponse-shaped JSON. The client never stores the refresh token.
When a sign-in requests e2ee:symmetric or e2ee:asymmetric, Ave appends the keys to the callback fragment. completeOAuthCallback, completeExpoOAuthCallback, and the embed’s onTokens merge them into the token response, and setTokensFromResponse stores them in the snapshot next to your tokens.Refreshes keep the stored keys. A sign-in with e2ee:reset replaces them, and the snapshot exposes the previous keys as appKeyBase64Old, appPublicKeyBase64Old, and appPrivateKeyBase64Old with appEncryptionWasReset set so you can re-encrypt existing data. signOut() clears keys along with tokens.AveSession stores keys wherever its storage adapter stores tokens. Choose the adapter with that in mind, and import keys with Web Crypto as shown in End-to-end encryption. setAppKeyBase64() replaces or clears the symmetric key if you manage it yourself.
Send await session.getValidIdToken() as a bearer token to your backend. On the server, verifyAveIdTokenFromAuthHeader from @ave-id/sdk/server verifies the signature, issuer, audience, and expiry, and returns the identity ID as subject:
import { verifyAveIdTokenFromAuthHeader } from "@ave-id/sdk/server";const principal = await verifyAveIdTokenFromAuthHeader(request.headers.get("authorization"), { clientId: process.env.AVE_CLIENT_ID!,});if (!principal) return new Response("Unauthorized", { status: 401 });const identityId = principal.subject;
Use verifyAveIdToken(token, { clientId }) when the token comes from somewhere other than an Authorization header.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Ave","description":"Passkey accounts, OAuth 2.0 and OpenID Connect, and end-to-end encryption keys delivered to your app.","colors":{"primary":"#D3D3D3","light":"#e5e5e5","dark":"#2c2c2c"},"logo":"https://mintcdn.com/lantharos/0MaQBpxqeVrKa_dc/images/Group6.png?fit=max\u0026auto=format\u0026n=0MaQBpxqeVrKa_dc\u0026q=85\u0026s=83958f45de83ce6cf8ecd56fdcb7f2e8","favicon":"https://mintcdn.com/lantharos/0MaQBpxqeVrKa_dc/images/Group6.png?fit=max\u0026auto=format\u0026n=0MaQBpxqeVrKa_dc\u0026q=85\u0026s=83958f45de83ce6cf8ecd56fdcb7f2e8","appearance":{"default":"dark"},"background":{"decoration":"gradient"},"navbar":{"links":[{"href":"https://devs.aveid.net","label":"Developer Portal"}]},"fonts":{"family":"Poppins","weight":500},"errors":{"404":{"redirect":false,"title":"Page not found","description":"The page you are looking for moved or no longer exists. Use the sidebar or search to find the latest integration guide."}},"metadata":{"timestamp":true},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"lantharos","hasAudioNarration":false,"actualSubdomain":"lantharos","customDomains":["docs.aveid.net"],"gitSource":{"type":"github","owner":"lantharos","repo":"ave","deployBranch":"main","contentDirectory":"ave-docs","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6ab9b626a3c670255a7ca0ea","collectionId":"3a4b0c3c-0d0c-4f86-8364-52805760d8df","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6ab9b626a3c670255a7ca0ea"},"feedback":{"thumbs":true,"agentFeedback":true},"entitlements":{},"buildId":"6ab9b626a3c670255a7ca0ea","clientVersion":"0.0.3966","searchFilterCounts":[{"language":"default","tag":"Guides","count":10},{"language":"default","tag":"Security","count":6},{"language":"default","tag":"Sign-in","count":5},{"language":"default","tag":"Start","count":4},{"language":"default","tag":"SDKs","count":4},{"language":"default","tag":"API Reference","count":3},{"language":"default","tag":"Endpoints","count":3},{"language":"default","tag":"JavaScript SDK","count":3},{"language":"default","tag":"Frameworks","count":2},{"language":"default","tag":"Encryption","count":2}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-v7-file-tree","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"pause-universal-search-reconcile","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"per-site-search-delta","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-private-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-nav-generations","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-agent-model-picker","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"isAtlas":false,"googleFontsInlined":true},"customCss":[],"page":{"pagePath":"guides/ave-session-and-tokens","slug":"/guides/ave-session-and-tokens","pageMetadata":{"title":"Ave Session","description":"Persist OAuth tokens, refresh safely, and keep framework auth clients supplied with fresh ID tokens.","href":"/guides/ave-session-and-tokens"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Persist OAuth tokens, refresh safely, and keep framework auth clients supplied with fresh ID tokens.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,p:`p`,pre:`pre`,span:`span`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Tip}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Tip)_missingMdxReference(`Tip`,true);return _jsxs(_Fragment,{children:[_jsxs(_components.p,{children:[`OAuth tokens expire on a short clock. That is separate from how long a user should stay signed in. When your app requests `,_jsx(_components.code,{children:`offline_access`}),`, Ave issues a refresh token so your app can rotate tokens without sending the user through consent again.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`AveSession`}),` gives you one supported lifecycle for that work: persist the token bundle and any encryption keys, refresh before expiry, collapse duplicate refresh calls, broadcast changes across tabs, and save rotated refresh tokens atomically.`]}),`\n`,_jsx(Heading,{level:`2`,id:`when-to-use-it`,children:`When to use it`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`You requested `,_jsx(_components.code,{children:`offline_access`}),` and want refresh handled for you.`]}),`\n`,_jsx(_components.li,{children:`You requested an encryption scope and want the keys kept next to the tokens.`}),`\n`,_jsxs(_components.li,{children:[`You need a fresh `,_jsx(_components.code,{children:`id_token`}),` for Convex, your API, or another auth client.`]}),`\n`,_jsx(_components.li,{children:`You want to avoid duplicated refresh calls, stale refresh tokens, and cold-start races.`}),`\n`,_jsx(_components.li,{children:`You need adapters for Convex, Svelte, or Expo.`}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`disconnected-apps`,children:`Disconnected apps`}),`\n`,_jsxs(_components.p,{children:[`Disconnecting an app in Ave invalidates its refresh tokens and access to Ave APIs for the selected identity, and deletes its encryption keys for that identity. Handle a definitive `,_jsx(_components.code,{children:`invalid_grant`}),` by clearing the app session and starting sign-in again. Reconnecting requires consent, does not reactivate old tokens, and provisions new encryption keys.`]}),`\n`,_jsx(_components.p,{children:`An ID token already accepted by another service remains subject to that service’s session policy and the token’s expiry. Signing out locally only clears the local session.`}),`\n`,_jsx(Heading,{level:`2`,id:`create-a-session`,children:`Create a session`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`19`,language:`typescript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`typescript`,children:_jsxs(_components.code,{language:`typescript`,numberOfLines:`19`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`import`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` { `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`AveSession`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`createLocalStorageAdapter`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` } `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`from`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"@ave-id/sdk\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`;`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`import`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` { `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`completeOAuthCallback`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` } `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`from`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"@ave-id/sdk/client\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`;`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`const`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4FC1FF`},children:` session`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` =`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` new`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:` AveSession`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`({`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` oauth:`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` clientId:`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` process`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`env`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4FC1FF`},children:`AVE_CLIENT_ID`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`!`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` redirectUri:`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"https://yourapp.com/callback\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` },`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` storage:`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:` createLocalStorageAdapter`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(),`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` devtools:`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` process`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`env`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4FC1FF`},children:`NODE_ENV`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` ===`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"development\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`});`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`await`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:` completeOAuthCallback`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`session`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` clientId:`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` process`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`env`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4FC1FF`},children:`AVE_CLIENT_ID`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`!`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` redirectUri:`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"https://yourapp.com/callback\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`});`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`await`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` session`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:`hydrate`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`();`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`const`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4FC1FF`},children:` idToken`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` =`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:` await`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` session`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:`getValidIdToken`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`();`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`completeOAuthCallback`}),` runs `,_jsx(_components.code,{children:`finishPkceLogin`}),` and `,_jsx(_components.code,{children:`setTokensFromResponse`}),` together. Use it on your OAuth callback route, then call `,_jsx(_components.code,{children:`hydrate()`}),` during app startup.`]}),`\n`,_jsxs(_components.p,{children:[`If the redirect carries encryption keys in its fragment, `,_jsx(_components.code,{children:`finishPkceLogin`}),` merges them into the token response and removes them from the URL. `,_jsx(_components.code,{children:`session.getAppKeyBase64()`}),`, `,_jsx(_components.code,{children:`getAppPublicKeyBase64()`}),`, and `,_jsx(_components.code,{children:`getAppPrivateKeyBase64()`}),` return the stored keys after `,_jsx(_components.code,{children:`hydrate()`}),`.`]}),`\n`,_jsx(Tip,{children:_jsxs(_components.p,{children:[`Set `,_jsx(_components.code,{children:`devtools: true`}),` only in development. It exposes `,_jsx(_components.code,{children:`window.__aveSessionDev`}),` with state, expiry helpers, and `,_jsx(_components.code,{children:`lastRefreshError`}),`.`]})}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`getValidIdToken()`}),` waits for proactive refresh when the JWT is near expiry. `,_jsx(_components.code,{children:`createLocalStorageAdapter()`}),` keeps the refresh token and any encryption keys in `,_jsx(_components.code,{children:`localStorage`}),`. For stricter setups, use `,_jsx(_components.code,{children:`createMemoryStorage()`}),`, your own `,_jsx(_components.code,{children:`AveSessionStorage`}),`, or a backend-for-frontend with `,_jsx(_components.code,{children:`customRefresh`}),`.`]}),`\n`,_jsx(Heading,{level:`2`,id:`convex`,children:`Convex`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`7`,language:`typescript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`typescript`,children:_jsxs(_components.code,{language:`typescript`,numberOfLines:`7`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`import`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` { `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`ConvexReactClient`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` } `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`from`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"convex/react\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`;`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`import`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` { `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`wireAveSessionToConvex`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` } `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`from`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"@ave-id/sdk/convex\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`;`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`const`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4FC1FF`},children:` convex`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` =`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` new`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:` ConvexReactClient`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4FC1FF`},children:`CONVEX_URL`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`await`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` session`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:`hydrate`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`();`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:`wireAveSessionToConvex`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`convex`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`session`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Call `,_jsx(_components.code,{children:`session.setTokensFromResponse`}),` after login. `,_jsx(_components.code,{children:`wireAveSessionToConvex`}),` passes a function that calls `,_jsx(_components.code,{children:`getValidIdToken()`}),` so Convex always receives a valid token.`]}),`\n`,_jsx(Heading,{level:`2`,id:`svelte`,children:`Svelte`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`4`,language:`typescript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`typescript`,children:_jsxs(_components.code,{language:`typescript`,numberOfLines:`4`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`import`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` { `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`aveSessionToStore`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` } `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`from`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"@ave-id/sdk/svelte\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`;`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`const`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4FC1FF`},children:` sessionStore`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` =`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:` aveSessionToStore`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`session`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`// sessionStore.subscribe(...) — status + snapshot`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Hydrate in `,_jsx(_components.code,{children:`onMount`}),` before relying on authenticated UI.`]}),`\n`,_jsx(Heading,{level:`2`,id:`expo`,children:`Expo`}),`\n`,_jsxs(_components.p,{children:[`Native Expo has no Web Crypto for PKCE SHA-256. Configure `,_jsx(_components.code,{children:`expo-crypto`}),` once with `,_jsx(_components.code,{children:`configureAveSdkForExpo`}),` from `,_jsx(_components.code,{children:`@ave-id/sdk/expo-session`}),`, then use `,_jsx(_components.code,{children:`AveSession`}),` with `,_jsx(_components.code,{children:`createSecureStoreAdapter`}),` and `,_jsx(_components.code,{children:`completeExpoOAuthCallback`}),`. See `,_jsx(_components.a,{href:`/guides/expo-auth-session`,children:`Expo with AuthSession`}),`.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`27`,language:`typescript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`typescript`,children:_jsxs(_components.code,{language:`typescript`,numberOfLines:`27`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`import`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` *`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:` as`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` ExpoCrypto`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:` from`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"expo-crypto\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`;`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`import`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` *`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:` as`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` SecureStore`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:` from`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"expo-secure-store\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`;`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`import`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` *`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:` as`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` WebBrowser`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:` from`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"expo-web-browser\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`;`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`import`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` AveSession`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` completeExpoOAuthCallback`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` configureAveSdkForExpo`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` createSecureStoreAdapter`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` initExpoOAuthBrowserSession`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` onExpoAppForegroundRefresh`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` warmUpExpoAuthBrowser`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`} `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`from`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"@ave-id/sdk/expo-session\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`;`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`import`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` { `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`AppState`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` } `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`from`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"react-native\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`;`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:`initExpoOAuthBrowserSession`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`WebBrowser`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:`configureAveSdkForExpo`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`ExpoCrypto`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`const`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4FC1FF`},children:` session`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` =`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` new`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:` AveSession`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`({`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` oauth:`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` { `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`clientId:`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"...\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`redirectUri:`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"myapp://callback\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` },`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` storage:`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:` createSecureStoreAdapter`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`SecureStore`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`),`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` crossTabSync:`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` false`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`});`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:`onExpoAppForegroundRefresh`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`AppState`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`session`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`// Optional: in your login screen component`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`// useEffect(() => warmUpExpoAuthBrowser(WebBrowser), []);`})}),`\n`]})})}),`\n`,_jsx(Heading,{level:`2`,id:`backend-refresh`,children:`Backend refresh`}),`\n`,_jsxs(_components.p,{children:[`Pass `,_jsx(_components.code,{children:`customRefresh`}),` in `,_jsx(_components.code,{children:`AveSession`}),` options to POST to your own `,_jsx(_components.code,{children:`/api/session/refresh`}),` endpoint. That endpoint can read an HttpOnly cookie and return `,_jsx(_components.code,{children:`TokenResponse`}),`-shaped JSON. The client never stores the refresh token.`]}),`\n`,_jsx(Heading,{level:`2`,id:`encryption-keys`,children:`Encryption keys`}),`\n`,_jsxs(_components.p,{children:[`When a sign-in requests `,_jsx(_components.code,{children:`e2ee:symmetric`}),` or `,_jsx(_components.code,{children:`e2ee:asymmetric`}),`, Ave appends the keys to the callback fragment. `,_jsx(_components.code,{children:`completeOAuthCallback`}),`, `,_jsx(_components.code,{children:`completeExpoOAuthCallback`}),`, and the embed’s `,_jsx(_components.code,{children:`onTokens`}),` merge them into the token response, and `,_jsx(_components.code,{children:`setTokensFromResponse`}),` stores them in the snapshot next to your tokens.`]}),`\n`,_jsxs(_components.p,{children:[`Refreshes keep the stored keys. A sign-in with `,_jsx(_components.code,{children:`e2ee:reset`}),` replaces them, and the snapshot exposes the previous keys as `,_jsx(_components.code,{children:`appKeyBase64Old`}),`, `,_jsx(_components.code,{children:`appPublicKeyBase64Old`}),`, and `,_jsx(_components.code,{children:`appPrivateKeyBase64Old`}),` with `,_jsx(_components.code,{children:`appEncryptionWasReset`}),` set so you can re-encrypt existing data. `,_jsx(_components.code,{children:`signOut()`}),` clears keys along with tokens.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`AveSession`}),` stores keys wherever its storage adapter stores tokens. Choose the adapter with that in mind, and import keys with Web Crypto as shown in `,_jsx(_components.a,{href:`/guides/end-to-end-encryption`,children:`End-to-end encryption`}),`. `,_jsx(_components.code,{children:`setAppKeyBase64()`}),` replaces or clears the symmetric key if you manage it yourself.`]}),`\n`,_jsx(Heading,{level:`2`,id:`dev-tools`,children:`Dev tools`}),`\n`,_jsxs(_components.p,{children:[`With `,_jsx(_components.code,{children:`devtools: true`}),`, `,_jsx(_components.code,{children:`window.__aveSessionDev`}),` exposes `,_jsx(_components.code,{children:`getState()`}),`, expiry helpers, and `,_jsx(_components.code,{children:`lastRefreshError`}),` in development builds.`]}),`\n`,_jsx(Heading,{level:`2`,id:`server-apis`,children:`Server APIs`}),`\n`,_jsxs(_components.p,{children:[`Send `,_jsx(_components.code,{children:`await session.getValidIdToken()`}),` as a bearer token to your backend. On the server, `,_jsx(_components.code,{children:`verifyAveIdTokenFromAuthHeader`}),` from `,_jsx(_components.code,{children:`@ave-id/sdk/server`}),` verifies the signature, issuer, audience, and expiry, and returns the identity ID as `,_jsx(_components.code,{children:`subject`}),`:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`8`,language:`typescript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`typescript`,children:_jsxs(_components.code,{language:`typescript`,numberOfLines:`8`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`import`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` { `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`verifyAveIdTokenFromAuthHeader`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` } `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`from`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"@ave-id/sdk/server\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`;`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`const`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4FC1FF`},children:` principal`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` =`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:` await`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:` verifyAveIdTokenFromAuthHeader`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`request`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`headers`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:`get`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"authorization\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`), {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` clientId:`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` process`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`env`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4FC1FF`},children:`AVE_CLIENT_ID`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`!`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`});`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`if`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` (`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`!`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`principal`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`) `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`return`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:` new`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:` Response`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"Unauthorized\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, { `}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`status:`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:` 401`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` });`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`const`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4FC1FF`},children:` identityId`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` =`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` principal`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`subject`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`;`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Use `,_jsx(_components.code,{children:`verifyAveIdToken(token, { clientId })`}),` when the token comes from somewhere other than an `,_jsx(_components.code,{children:`Authorization`}),` header.`]}),`\n`,_jsx(Heading,{level:`2`,id:`related`,children:`Related`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/guides/convex-custom-auth`,children:`Convex custom auth`}),` — `,_jsx(_components.code,{children:`applicationID`}),`, which token to pass`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/guides/convex-custom-auth#sessions-still-flaky`,children:`Why sessions still fail`}),` — troubleshooting matrix`]}),`\n`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Ave Session","description":"Persist OAuth tokens, refresh safely, and keep framework auth clients supplied with fresh ID tokens.","href":"/guides/ave-session-and-tokens"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"When to use it","slug":"when-to-use-it","depth":2,"children":[]},{"title":"Disconnected apps","slug":"disconnected-apps","depth":2,"children":[]},{"title":"Create a session","slug":"create-a-session","depth":2,"children":[]},{"title":"Convex","slug":"convex","depth":2,"children":[]},{"title":"Svelte","slug":"svelte","depth":2,"children":[]},{"title":"Expo","slug":"expo","depth":2,"children":[]},{"title":"Backend refresh","slug":"backend-refresh","depth":2,"children":[]},{"title":"Encryption keys","slug":"encryption-keys","depth":2,"children":[]},{"title":"Dev tools","slug":"dev-tools","depth":2,"children":[]},{"title":"Server APIs","slug":"server-apis","depth":2,"children":[]},{"title":"Related","slug":"related","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"lantharos","siteName":"Ave","title":"Ave Session - Ave","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-09-28T00:19:45.081Z","gitLastModified":"2026-09-28T00:19:37.000Z","originalFileLocation":"guides/ave-session-and-tokens.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"dark\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Persist OAuth tokens, refresh safely, and keep framework auth clients supplied with fresh ID tokens.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Ave\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/lantharos/yCo3jeUTtvlE0Bwd/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/lantharos/yCo3jeUTtvlE0Bwd/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/lantharos/yCo3jeUTtvlE0Bwd/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/lantharos/yCo3jeUTtvlE0Bwd/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/lantharos/yCo3jeUTtvlE0Bwd/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/lantharos/yCo3jeUTtvlE0Bwd/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/lantharos/yCo3jeUTtvlE0Bwd/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/lantharos/yCo3jeUTtvlE0Bwd/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/lantharos/yCo3jeUTtvlE0Bwd/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Ave Session - Ave\">\u003cmeta data-mint-head property=\"og:description\" content=\"Persist OAuth tokens, refresh safely, and keep framework auth clients supplied with fresh ID tokens.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Ave\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.aveid.net/guides/ave-session-and-tokens\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://lantharos.mintlify.app/_mintlify/api/og/v2?division=Sign-in\u0026amp;title=Ave+Session\u0026amp;description=Persist+OAuth+tokens%2C+refresh+safely%2C+and+keep+framework+auth+clients+supplied+with+fresh+ID+tokens.\u0026amp;theme=376a01153fbdcc2c7faead96\u0026amp;signature=f2180861946cdd43f8098aa47dfdef38ffa907791bc1f24fa5ac6a7b322dae78\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Ave Session - Ave\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Persist OAuth tokens, refresh safely, and keep framework auth clients supplied with fresh ID tokens.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://lantharos.mintlify.app/_mintlify/api/og/v2?division=Sign-in\u0026amp;title=Ave+Session\u0026amp;description=Persist+OAuth+tokens%2C+refresh+safely%2C+and+keep+framework+auth+clients+supplied+with+fresh+ID+tokens.\u0026amp;theme=376a01153fbdcc2c7faead96\u0026amp;signature=f2180861946cdd43f8098aa47dfdef38ffa907791bc1f24fa5ac6a7b322dae78\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/lantharos/yCo3jeUTtvlE0Bwd/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Ave\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#D3D3D3\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.aveid.net/guides/ave-session-and-tokens\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/guides/ave-session-and-tokens.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.aveid.net/#organization\",\"name\":\"Ave\",\"url\":\"https://docs.aveid.net\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/lantharos/0MaQBpxqeVrKa_dc/images/Group6.png?fit=max\u0026auto=format\u0026n=0MaQBpxqeVrKa_dc\u0026q=85\u0026s=83958f45de83ce6cf8ecd56fdcb7f2e8\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.aveid.net#website\",\"name\":\"Ave\",\"url\":\"https://docs.aveid.net\",\"publisher\":{\"@id\":\"https://docs.aveid.net/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.aveid.net/guides/ave-session-and-tokens#webpage\",\"url\":\"https://docs.aveid.net/guides/ave-session-and-tokens\",\"name\":\"Ave Session\",\"description\":\"Persist OAuth tokens, refresh safely, and keep framework auth clients supplied with fresh ID tokens.\",\"dateModified\":\"2026-09-28T00:19:37.000Z\",\"isPartOf\":{\"@id\":\"https://docs.aveid.net#website\"},\"breadcrumb\":{\"@id\":\"https://docs.aveid.net/guides/ave-session-and-tokens#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.aveid.net/guides/ave-session-and-tokens#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Sign-in\",\"item\":\"https://docs.aveid.net/guides/oauth-authorization-code-flow\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Ave Session\",\"item\":\"https://docs.aveid.net/guides/ave-session-and-tokens\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.aveid.net/guides/ave-session-and-tokens#article\",\"headline\":\"Ave Session\",\"name\":\"Ave Session\",\"description\":\"Persist OAuth tokens, refresh safely, and keep framework auth clients supplied with fresh ID tokens.\",\"url\":\"https://docs.aveid.net/guides/ave-session-and-tokens\",\"mainEntityOfPage\":{\"@id\":\"https://docs.aveid.net/guides/ave-session-and-tokens#webpage\"},\"dateModified\":\"2026-09-28T00:19:37.000Z\",\"publisher\":{\"@id\":\"https://docs.aveid.net/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.aveid.net#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Ave\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Ave","nav":{"global":null,"tabs":[{"tab":"Start","pages":[{"title":"Start","href":""}]},{"tab":"Guides","groups":[{"group":"Encryption","pages":[{"title":"End-to-end encryption","href":"/guides/end-to-end-encryption"},{"title":"E2EE integration checklist","href":"/guides/e2ee-integration-checklist"}]},{"group":"Sign-in","pages":[{"title":"OAuth authorization code flow","href":"/guides/oauth-authorization-code-flow"},{"title":"PKCE for public clients","href":"/guides/pkce-for-public-clients"},{"title":"Server-side confidential clients","href":"/guides/server-side-confidential-clients"},{"title":"Scopes and claims","description":"Every available scope, the claims and keys it adds, and how to request scopes safely.","href":"/guides/scopes-and-claims"},{"title":"Ave Session","href":"/guides/ave-session-and-tokens"}]},{"group":"Building on Ave","pages":[{"title":"App workspaces and permissions","description":"Use Ave identity with workspaces and authorization managed by your app.","href":"/guides/app-authorization"}]},{"group":"Frameworks","pages":[{"title":"Expo with AuthSession","href":"/guides/expo-auth-session"},{"title":"Convex custom auth","href":"/guides/convex-custom-auth"}]}]},{"tab":"SDKs","pages":[{"title":"SDKs","href":"/sdk/javascript-sdk"}]},{"tab":"API Reference","pages":[{"title":"API Reference","href":"/api/overview"}]},{"tab":"Security","pages":[{"title":"Security","href":"/security/encryption-model-and-key-lifecycle"}]}]},"title":"Ave Session - Ave","buildId":"dpl_cadrRc5H9XQiJQbDFN5mcYRs2PAj","deploymentId":"dpl_cadrRc5H9XQiJQbDFN5mcYRs2PAj","dynamics":[],"chunks":[]}