The field companion lists today's site visits after hosted sign-in returns through a deep link. The session token stays in secure storage.

Clone [starters/expo](https://github.com/authdog/samples/tree/main/starters/expo). SDK reference: [React Native / Expo](/docs/frameworks/expo).

The job list answers who the technician is on the device. Client state is UX, not a security boundary. Your API must validate the bearer. Apply [authorization](/docs/concepts/authorization) there.

## What you need

| Requirement | Detail |
| --- | --- |
| Public key | `pk_...` from the [console](https://console.authdog.com) |
| Environment | Copy `.env.example` to `.env` and set `EXPO_PUBLIC_PK_AUTHDOG` |
| Secret key | Never put `sk_...` in the app |
| Callback | Register the deep-link callback. Local default: `authdog-authn://callback` |

## Run

```bash
npm install
npx expo start
```

Open the project in Expo Go or a simulator. Tap **Sign in**, finish the hosted Account portal, and return through the deep link. You should see `job_18` (Pier 4, replace meter) and `job_19` (Warehouse B, calibrate sensor).

## Jobs

`handleRedirect` stores `?token=` after a structure check only. `fetchUser()` validates it through userinfo. The visits render only after that call. This example uses `expo-secure-store`. Do not ship the in-memory fallback.

```tsx
// App.tsx
import { useEffect } from "react"
import { Button, Linking, Text } from "react-native"
import * as SecureStore from "expo-secure-store"
import {
  AuthdogProvider,
  createSecureStoreAdapter,
  useRedirectHandler,
  useSignIn,
  useUser,
} from "@authdog/react-native"

const publicKey = process.env.EXPO_PUBLIC_PK_AUTHDOG ?? ""

function Home() {
  const { signIn } = useSignIn()
  const { handleRedirect } = useRedirectHandler()
  const { fetchUser, isAuthenticated } = useUser()
  const redirectUrl = "authdog-authn://callback"

  useEffect(() => {
    Linking.getInitialURL().then((url) => {
      if (url) handleRedirect(url)
    })
    const sub = Linking.addEventListener("url", ({ url }) => handleRedirect(url))
    return () => sub.remove()
  }, [handleRedirect])

  useEffect(() => {
    if (isAuthenticated) fetchUser()
  }, [isAuthenticated, fetchUser])

  if (!isAuthenticated) {
    return <Button title="Sign in" onPress={() => signIn(redirectUrl)} />
  }

  return (
    <>
      <Text>job_18 · Pier 4 · Replace meter · 08:00–10:00</Text>
      <Text>job_19 · Warehouse B · Calibrate sensor · 11:30–12:00</Text>
    </>
  )
}

export default function App() {
  return (
    <AuthdogProvider
      publicKey={publicKey}
      storage={createSecureStoreAdapter(SecureStore)}
    >
      <Home />
    </AuthdogProvider>
  )
}
```
