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

# Authentication

> Handle authentication flows on mobile devices

Uplink provides specialized methods for waiting for users to complete authentication on their devices. Since real users log themselves in on real mobile devices, authentication flows work naturally.

<Tip>
  **The Uplink Advantage**: Users authenticate themselves on their own devices. No credential management needed. Simply wait for the user to complete authentication, then automate the rest.
</Tip>

## Methods

### `page.authenticate()`

Navigates to a URL and waits for authentication to complete.

```typescript theme={null}
page.authenticate(
  startURL: string,
  authEvaluator: AuthEvaluator,
  options?: AuthenticateOptions
): Promise<AuthStatus>
```

**Parameters:**

* `startURL`: URL to navigate to for authentication
* `authEvaluator`: Function that checks if authentication is complete
* `options` (optional): Authentication options

**AuthEvaluator:**

```typescript theme={null}
type AuthEvaluator = (page: Page) => boolean | Promise<boolean>
```

**Options:**

```typescript theme={null}
interface AuthenticateOptions {
  timeout?: number  // Timeout in milliseconds (default: 90000)
}
```

**Returns:** `Promise<AuthStatus>` - Either `'authenticated'` or `'aborted'`

**Examples:**

```typescript theme={null}
// Wait for session cookie
const status = await page.authenticate(
  'https://example.com/login',
  async (page) => {
    const cookies = await page.cookies('https://example.com')
    return cookies.some(c => c.name === 'session_token')
  },
  { timeout: 90000 }
)

if (status === 'authenticated') {
  console.log('Authentication successful')
}

// Wait for URL change
const status = await page.authenticate(
  'https://example.com/oauth/authorize',
  async (page) => {
    const url = await page.url()
    return url.includes('/dashboard')
  }
)
```

### `page.waitForAuthentication()`

Waits for authentication to complete without navigating.

```typescript theme={null}
page.waitForAuthentication(
  authEvaluator: AuthEvaluator,
  options?: AuthenticateOptions
): Promise<AuthStatus>
```

**Parameters:**

* `authEvaluator`: Function that checks if authentication is complete
* `options` (optional): Authentication options

**Returns:** `Promise<AuthStatus>` - Either `'authenticated'` or `'aborted'`

**Example:**

```typescript theme={null}
// User manually logs in on the device
await page.goto('https://example.com/login')

// Wait for them to complete authentication
const status = await page.waitForAuthentication(
  async (page) => {
    const url = await page.url()
    return url.includes('/dashboard')
  },
  { timeout: 120000 }  // 2 minutes
)

if (status === 'authenticated') {
  console.log('User logged in successfully')
}
```

## Complete examples

### OAuth flow

```typescript theme={null}
async function handleOAuthLogin(page) {
  const status = await page.authenticate(
    'https://app.example.com/oauth/google',
    async (page) => {
      // Check if we're back at the app with an auth token
      const url = await page.url()
      if (!url.includes('app.example.com')) return false

      // Verify we have the auth cookie
      const cookies = await page.cookies('https://app.example.com')
      return cookies.some(c => c.name === 'oauth_token')
    },
    { timeout: 120000 }  // Give user 2 minutes to log in
  )

  if (status === 'authenticated') {
    console.log('OAuth login successful')
    return true
  } else {
    console.log('OAuth login aborted or timed out')
    return false
  }
}

const success = await handleOAuthLogin(page)
if (success) {
  // Continue with authenticated session
  await page.goto('https://app.example.com/dashboard')
}
```

### Social login

```typescript theme={null}
async function socialLogin(page, provider) {
  const status = await page.authenticate(
    `https://example.com/login/${provider}`,
    async (page) => {
      // User completes login on social provider's site
      // Check for success indicator
      const url = await page.url()

      if (url.includes('example.com/welcome')) {
        return true  // Redirected to welcome page
      }

      // Or check for authentication cookie
      const cookies = await page.cookies('https://example.com')
      return cookies.some(c => c.name === 'auth_session')
    },
    { timeout: 180000 }  // 3 minutes for social login
  )

  return status === 'authenticated'
}

// Try Google login
const success = await socialLogin(page, 'google')
console.log('Google login:', success ? 'success' : 'failed')
```

### Two-factor authentication

```typescript theme={null}
async function waitForTwoFactorLogin(page) {
  // Navigate to login page
  await page.goto('https://example.com/login')

  // User enters their credentials and 2FA code on the device
  console.log('Waiting for user to complete login with 2FA...')

  const status = await page.waitForAuthentication(
    async (page) => {
      const url = await page.url()
      return url.includes('/dashboard')
    },
    { timeout: 180000 }  // Give user 3 minutes to enter credentials + 2FA
  )

  if (status === 'authenticated') {
    console.log('User successfully completed 2FA login')
    return true
  }

  return false
}

await waitForTwoFactorLogin(page)
```

### Session-based authentication

```typescript theme={null}
async function checkSession(page) {
  await page.goto('https://example.com')

  const status = await page.waitForAuthentication(
    async (page) => {
      const cookies = await page.cookies('https://example.com')
      const sessionCookie = cookies.find(c => c.name === 'session_id')

      if (!sessionCookie) return false

      // Optionally validate the session cookie
      const isValid = await page.evaluate(() => {
        return document.body.classList.contains('logged-in')
      })

      return isValid
    },
    { timeout: 10000 }
  )

  return status === 'authenticated'
}

const isAuthenticated = await checkSession(page)
if (!isAuthenticated) {
  console.log('No valid session, need to log in')
  // Proceed with login flow
}
```

### Mobile app authentication

```typescript theme={null}
async function appAuthentication(page) {
  // Navigate to the authentication start page
  const status = await page.authenticate(
    'https://example.com/app/auth',
    async (page) => {
      // Check for mobile-specific auth indicator
      const authToken = await page.evaluate(() => {
        return localStorage.getItem('auth_token')
      })

      if (!authToken) return false

      // Verify token is valid
      const url = await page.url()
      return url.includes('/app/home')
    },
    { timeout: 180000 }
  )

  if (status === 'authenticated') {
    // Get the auth token for API calls
    const token = await page.evaluate(() => {
      return localStorage.getItem('auth_token')
    })

    console.log('Authenticated, token:', token)
    return token
  }

  return null
}
```

## Best practices

<AccordionGroup>
  <Accordion title="Let users handle credentials" icon="user-shield">
    With Uplink, users authenticate themselves on their own devices:

    ```typescript theme={null}
    // Navigate to login page and wait - user handles the rest
    await page.authenticate(
      'https://example.com/login',
      async (page) => {
        const cookies = await page.cookies('https://example.com')
        return cookies.some(c => c.name === 'session')
      }
    )
    // Now automate authenticated actions
    ```
  </Accordion>

  <Accordion title="Use appropriate timeouts" icon="clock">
    Authentication often requires user interaction, so use longer timeouts:

    ```typescript theme={null}
    const status = await page.authenticate(
      url,
      evaluator,
      { timeout: 180000 }  // 3 minutes for complex auth
    )
    ```
  </Accordion>

  <Accordion title="Check multiple indicators" icon="list-check">
    Verify authentication using multiple methods:

    ```typescript theme={null}
    async (page) => {
      const url = await page.url()
      const cookies = await page.cookies('https://example.com')

      return url.includes('/dashboard') &&
             cookies.some(c => c.name === 'session_token')
    }
    ```
  </Accordion>

  <Accordion title="Handle aborted authentication" icon="xmark">
    Always handle the aborted case:

    ```typescript theme={null}
    const status = await page.authenticate(url, evaluator)

    if (status === 'aborted') {
      console.log('User closed authentication or it timed out')
      // Handle gracefully
    }
    ```
  </Accordion>

  <Accordion title="Store tokens after auth" icon="key">
    Extract and store authentication tokens for later use:

    ```typescript theme={null}
    if (status === 'authenticated') {
      const token = await page.evaluate(() => {
        return localStorage.getItem('token')
      })
      // Store token for API calls
    }
    ```
  </Accordion>
</AccordionGroup>

## Related

<CardGroup cols={2}>
  <Card title="Cookies" icon="cookie" href="/api-reference/page/cookies">
    Manage authentication cookies
  </Card>

  <Card title="Waiting" icon="hourglass" href="/api-reference/page/waiting">
    Wait for authentication indicators
  </Card>

  <Card title="Navigation" icon="compass" href="/api-reference/page/navigation">
    Navigate to auth pages
  </Card>

  <Card title="Page overview" icon="window-maximize" href="/api-reference/page/overview">
    Back to Page API overview
  </Card>
</CardGroup>
