> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ouim.me/llms.txt
> Use this file to discover all available pages before exploring further.

# CallbackPage

> Component for handling authentication callbacks after Logto redirect

## Overview

The `CallbackPage` component handles the authentication callback after users are redirected back from Logto. It processes the authentication code, exchanges it for tokens, and manages the post-authentication flow including popup and redirect scenarios.

## Installation

```bash theme={null}
npm install @ouim/logto-authkit
```

## Basic Usage

Create a callback route in your application:

```tsx app/callback/page.tsx theme={null}
import { CallbackPage } from '@ouim/logto-authkit'

export default function Callback() {
  return <CallbackPage />
}
```

## Props

<ParamField path="className" type="string">
  Additional CSS classes to apply to the container element.

  ```tsx theme={null}
  <CallbackPage className="bg-gray-50" />
  ```
</ParamField>

<ParamField path="loadingComponent" type="React.ReactNode">
  Custom component to display while processing authentication.

  ```tsx theme={null}
  <CallbackPage
    loadingComponent={
      <div className="flex items-center gap-2">
        <Spinner />
        <p>Please wait...</p>
      </div>
    }
  />
  ```
</ParamField>

<ParamField path="successComponent" type="React.ReactNode">
  Custom component to display after successful authentication.

  ```tsx theme={null}
  <CallbackPage
    successComponent={
      <div className="text-center">
        <CheckCircle className="text-green-500" />
        <p>Success! Taking you to your dashboard...</p>
      </div>
    }
  />
  ```
</ParamField>

<ParamField path="onSuccess" type="() => void">
  Callback function executed after successful authentication, before redirect/close.

  ```tsx theme={null}
  <CallbackPage
    onSuccess={() => {
      console.log('Authentication successful!')
      // Track analytics, etc.
    }}
  />
  ```
</ParamField>

<ParamField path="onError" type="(error: Error) => void">
  Callback function executed if authentication fails.

  ```tsx theme={null}
  <CallbackPage
    onError={error => {
      console.error('Auth failed:', error)
      // Show error message, redirect to error page, etc.
    }}
  />
  ```
</ParamField>

## How It Works

The `CallbackPage` component:

1. **Receives the auth code** from Logto redirect URL
2. **Exchanges code for tokens** using `useHandleSignInCallback()` from `@logto/react`
3. **Detects the flow type** (popup vs. redirect)
4. **Handles completion**:
   * **Popup flow**: Sends message to parent window and closes
   * **Redirect flow**: Redirects to home page (`/`)

## Flow Detection

The component automatically detects whether it's handling a popup or redirect flow:

```typescript theme={null}
const isPopup = (window.opener && window.opener !== window) || sessionStorage.getItem('simple_logto_popup_flow') === 'true'
```

* Checks if the window has an `opener` (parent window)
* Falls back to `sessionStorage` flag for cross-origin scenarios

## Popup Flow

For popup-based authentication:

1. Component detects it's in a popup
2. Processes authentication
3. Sends `SIGNIN_SUCCESS` message to parent window
4. Closes the popup

```typescript theme={null}
// Sends message to parent
window.opener.postMessage({ type: 'SIGNIN_SUCCESS' }, window.location.origin)

// Closes popup after small delay
setTimeout(() => {
  window.close()
}, 100)
```

### Fallback Mechanism

If `window.opener` is unavailable (some browsers clear it), falls back to localStorage:

```typescript theme={null}
localStorage.setItem('simple_logto_signin_complete', Date.now().toString())
```

<Info>The parent window listens for both `postMessage` and `localStorage` events to handle popup completion.</Info>

## Redirect Flow

For full-page redirect authentication:

1. Component detects it's NOT in a popup
2. Processes authentication
3. Redirects to home page (`/`)

```typescript theme={null}
if (!isPopup) {
  window.location.href = '/'
}
```

## Examples

### Basic Setup (Next.js App Router)

```tsx app/callback/page.tsx theme={null}
import { CallbackPage } from '@ouim/logto-authkit'

export default function Callback() {
  return <CallbackPage />
}
```

### With Custom Loading State

```tsx theme={null}
import { CallbackPage } from '@ouim/logto-authkit'
import { Loader2 } from 'lucide-react'

export default function Callback() {
  return (
    <CallbackPage
      loadingComponent={
        <div className="flex flex-col items-center gap-4">
          <Loader2 className="h-8 w-8 animate-spin text-blue-500" />
          <p className="text-lg font-medium">Signing you in...</p>
          <p className="text-sm text-gray-500">Please wait a moment</p>
        </div>
      }
    />
  )
}
```

### With Success Tracking

```tsx theme={null}
import { CallbackPage } from '@ouim/logto-authkit'
import { useRouter } from 'next/navigation'

export default function Callback() {
  const router = useRouter()

  return (
    <CallbackPage
      onSuccess={() => {
        // Track successful authentication
        if (typeof window !== 'undefined' && window.analytics) {
          window.analytics.track('User Signed In', {
            method: 'logto',
            timestamp: new Date().toISOString(),
          })
        }
      }}
      onError={error => {
        console.error('Authentication error:', error)
        // Redirect to error page
        router.push('/auth/error')
      }}
    />
  )
}
```

### Custom Styling

```tsx theme={null}
import { CallbackPage } from '@ouim/logto-authkit'

export default function Callback() {
  return (
    <div className="min-h-screen bg-gradient-to-br from-blue-500 to-purple-600">
      <CallbackPage
        className="flex items-center justify-center min-h-screen"
        loadingComponent={
          <div className="bg-white rounded-lg shadow-xl p-8">
            <div className="flex items-center gap-3">
              <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-blue-500" />
              <p className="text-gray-700">Authenticating...</p>
            </div>
          </div>
        }
      />
    </div>
  )
}
```

### With Custom Redirect

```tsx theme={null}
import { CallbackPage } from '@ouim/logto-authkit'

export default function Callback() {
  return (
    <CallbackPage
      onSuccess={() => {
        // Check if this is popup flow
        const isPopup = (window.opener && window.opener !== window) || sessionStorage.getItem('simple_logto_popup_flow') === 'true'

        if (!isPopup) {
          // Custom redirect for non-popup flow
          window.location.href = '/dashboard'
        }
      }}
    />
  )
}
```

## Default UI

If no custom components are provided, the callback page displays:

### Loading State

```tsx theme={null}
<div className="flex items-center gap-2">
  <Spinner /> {/* Animated spinner */}
  <div className="text-lg text-slate-500">Signing you in...</div>
</div>
```

### Success State

```tsx theme={null}
<div className="flex items-center gap-2">
  <Spinner />
  <div className="text-lg text-slate-500">Authentication complete! Redirecting...</div>
</div>
```

## Session Storage Flag

For popup flows, your sign-in page should set a flag:

```tsx app/signin/page.tsx theme={null}
'use client'

import { useEffect } from 'react'
import { useAuth } from '@ouim/logto-authkit'
import { useSearchParams } from 'next/navigation'

export default function SignIn() {
  const { signIn } = useAuth()
  const searchParams = useSearchParams()
  const isPopup = searchParams.get('popup') === 'true'

  useEffect(() => {
    if (isPopup) {
      sessionStorage.setItem('simple_logto_popup_flow', 'true')
    }
    signIn('/callback')
  }, [signIn, isPopup])

  return <div>Redirecting to sign in...</div>
}
```

## Error Handling

The component handles errors during authentication:

```typescript theme={null}
try {
  // Process authentication
} catch (error) {
  console.error('Authentication callback error:', error)
  if (onError) {
    onError(error as Error)
  }
}
```

Common errors:

* Invalid authorization code
* Token exchange failure
* Network errors
* CORS issues

## Best Practices

<AccordionGroup>
  <Accordion title="Create a dedicated route">
    Always use a dedicated route like `/callback` or `/auth/callback` for handling authentication callbacks.
  </Accordion>

  <Accordion title="Configure Logto redirect URI">
    Make sure your Logto application's redirect URI matches your callback route exactly.
  </Accordion>

  <Accordion title="Handle both flows">
    The component automatically handles both popup and redirect flows - no additional configuration needed.
  </Accordion>

  <Accordion title="Add error tracking">Use the `onError` callback to track authentication failures in your monitoring system.</Accordion>

  <Accordion title="Customize user experience">
    Provide custom loading and success components that match your application's design.
  </Accordion>
</AccordionGroup>

## Configuration in Logto

In your Logto application settings, add your callback URL:

```
https://yourdomain.com/callback
```

For local development:

```
http://localhost:3000/callback
```

## Troubleshooting

<Warning>
  **Popup doesn't close**: Ensure your sign-in page sets the `simple_logto_popup_flow` sessionStorage flag when `?popup=true` is in the URL.
</Warning>

<Warning>**Infinite redirect loop**: Check that your Logto redirect URI exactly matches your callback route.</Warning>

<Warning>**CORS errors**: Ensure your Logto application's allowed origins include your application's domain.</Warning>

<Check>The component automatically cleans up the `simple_logto_popup_flow` flag after successful authentication.</Check>

## Related

<CardGroup cols={2}>
  <Card title="AuthProvider" icon="shield-check" href="/logto-authkit/frontend/auth-provider">
    Configure authentication provider
  </Card>

  <Card title="useAuth Hook" icon="hook" href="/logto-authkit/frontend/use-auth">
    Access sign-in functionality
  </Card>

  <Card title="UserCenter" icon="user" href="/logto-authkit/frontend/user-center">
    User menu with sign-in button
  </Card>

  <Card title="Route Protection" icon="lock" href="/logto-authkit/frontend/route-protection">
    Protect authenticated routes
  </Card>
</CardGroup>
