Status
Package status is Current package. Expo SecureStore and WebBrowser adapters, XidProvider, and Expo Router route guard hook are implemented. A real IdP round-trip on production infrastructure is still pending manual verification.
All PKCE logic, token exchange, and session management live in @xid-kit/react-native; this package provides adapters and Expo Router integration only.
Provider setup
Inject createSecureStoreAdapter and createExpoWebBrowserAdapter into XidProvider. No top-level Expo module import is needed; adapters accept module instances so CI typecheck stays clean without Expo peer deps installed.
import * as SecureStore from 'expo-secure-store'
import * as WebBrowser from 'expo-web-browser'
import { XidProvider, createSecureStoreAdapter, createExpoWebBrowserAdapter } from '@xid-kit/expo'
const tokenCache = createSecureStoreAdapter({ secureStore: SecureStore })
const browser = createExpoWebBrowserAdapter({ webBrowser: WebBrowser })
export default function App() {
return (
<XidProvider
publishableKey="pk_live_..."
issuer="https://xid.dev"
clientId="your_client_id"
redirectUri="myapp://auth/callback"
tokenCache={tokenCache}
browser={browser}
>
<RootLayout />
</XidProvider>
)
}Sign in and sign out
import { useSignIn, useSignOut } from '@xid-kit/expo'
import { Button } from 'react-native'
function SignInScreen() {
const { signIn, signInState } = useSignIn()
return (
<Button
title={signInState.status === 'pending' ? 'Signing in...' : 'Sign In'}
onPress={() => void signIn()}
/>
)
}
function SignOutScreen() {
const { signOut } = useSignOut()
return <Button title="Sign Out" onPress={() => void signOut()} />
}Expo Router route guard
Call useProtectedRoute in a layout component. It reads isLoaded/isSignedIn from useAuth and calls replace from Expo Router inside a useEffect.
import { useProtectedRoute } from '@xid-kit/expo'
import { useRouter, usePathname } from 'expo-router'
export default function RootLayout() {
const router = useRouter()
const pathname = usePathname()
useProtectedRoute({
signInRoute: '/sign-in',
protectedRoute: '/(app)',
pathname,
replace: router.replace,
})
return <Slot />
}SecureStore key namespacing
Use keyPrefix to namespace keys under a custom prefix. The separator is . (dot), which is within the allowed character set for expo-secure-store.
const tokenCache = createSecureStoreAdapter({
secureStore: SecureStore,
keyPrefix: 'myapp',
// keys: 'myapp.xid.access_token', 'myapp.xid.refresh_token', etc.
})Exported API
| Export | Kind | Purpose |
|---|---|---|
XidProvider |
component | Re-export of @xid-kit/react-native XidProvider accepting tokenCache and browser adapters |
createSecureStoreAdapter |
function | TokenCache adapter backed by expo-secure-store; accepts secureStore instance and optional keyPrefix |
createExpoWebBrowserAdapter |
function | BrowserInterface adapter backed by expo-web-browser |
useSignIn |
hook | Re-export from @xid-kit/react-native: signIn, handleRedirect, signInState |
useSignOut |
hook | Re-export from @xid-kit/react-native: signOut, signOutState |
useProtectedRoute |
hook | Reads isLoaded/isSignedIn and calls Expo Router replace for route protection |
Known limitations
useAuth().isSignedInreflects theXidClientweb-cookie session state, which does not auto-populate from the local SecureStore tokens after token exchange. Reload client state explicitly after a successful sign-in.- This package provides only adapters and Expo Router integration. For the base React Native PKCE flow, see @xid-kit/react-native.