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

# Wait for Auth Success

# waitForAuthSuccess

Returns a promise that resolves with the authenticated user once the `authSuccess` event fires. Use this when you need to ensure authentication is fully complete — including MFA and other intermediate steps — before proceeding (for example, before loading wallets or accessing user data).

Before this: set up the Dynamic client (see [Setting up the Dynamic Client](/react-native/reference/client)).

## Why use this instead of listening to events?

Listening for `authSuccess` with `dynamicClient.auth.on` works, but it requires manual cleanup and doesn't handle edge cases like MFA flows where authentication pauses for user input. `waitForAuthSuccess` wraps this into a single promise that:

* Resolves when authentication completes (even after MFA or other intermediate steps)
* Rejects when authentication fails or is cancelled
* Supports an optional timeout

## Usage

```typescript theme={"system"}
import { dynamicClient } from '<path to client file>';

const user = await dynamicClient.auth.waitForAuthSuccess();
// Authentication complete — user and wallets are available
```

## Parameters

| Parameter | Type     | Description                                                              |
| --------- | -------- | ------------------------------------------------------------------------ |
| `timeout` | `number` | Maximum time in milliseconds to wait. Rejects with an error if exceeded. |

Pass options as an object:

```typescript theme={"system"}
dynamicClient.auth.waitForAuthSuccess({ timeout: 60_000 });
```

## Returns

`Promise<UserProfile>` — Resolves with the authenticated user profile.

## Behavior

* **User not yet authenticated**: Listens for `authSuccess` and resolves when it fires. If `authFailed` fires first, the promise rejects.
* **User already authenticated**: Waits briefly (500 ms grace period) for an incoming `authSuccess` event. If no event arrives, resolves with the current authenticated user. This handles the case where authentication completed moments before the call.
* **Timeout**: If `timeout` is set and neither `authSuccess` nor `authFailed` fires within that window, the promise rejects with a timeout error.

## Examples

### Wait for authentication before loading wallets

<Tabs>
  <Tab title="With UI auth flow">
    ```tsx React Native theme={"system"}
    import { dynamicClient } from '<path to client file>';
    import { useState } from 'react';
    import { View, Button, Text } from 'react-native';

    const LoginScreen = () => {
      const [status, setStatus] = useState('');

      const handleLogin = async () => {
        dynamicClient.ui.auth.show();

        try {
          const user = await dynamicClient.auth.waitForAuthSuccess();
          setStatus(`Authenticated: ${user.email}`);
          // Safe to access wallets now
        } catch (error) {
          setStatus(`Auth failed: ${error.message}`);
        }
      };

      return (
        <View>
          <Button title="Log in" onPress={handleLogin} />
          {status ? <Text>{status}</Text> : null}
        </View>
      );
    };
    ```
  </Tab>

  <Tab title="With email OTP">
    ```tsx React Native theme={"system"}
    import { dynamicClient } from '<path to client file>';
    import { useState } from 'react';
    import { View, TextInput, Button, Text } from 'react-native';

    const EmailLoginScreen = () => {
      const [email, setEmail] = useState('');
      const [otp, setOtp] = useState('');
      const [otpSent, setOtpSent] = useState(false);

      const handleSendOTP = async () => {
        await dynamicClient.auth.email.sendOTP(email);
        setOtpSent(true);
      };

      const handleVerifyOTP = async () => {
        await dynamicClient.auth.email.verifyOTP(otp);

        // Wait for auth to fully complete (including MFA if required)
        const user = await dynamicClient.auth.waitForAuthSuccess();

        // Now safe to check embedded wallet status
        const hasWallet = dynamicClient.wallets.embedded.hasWallet;
        console.log('Has embedded wallet:', hasWallet);
      };

      return (
        <View>
          {!otpSent ? (
            <View>
              <TextInput
                value={email}
                onChangeText={setEmail}
                placeholder="Enter your email"
              />
              <Button title="Send OTP" onPress={handleSendOTP} />
            </View>
          ) : (
            <View>
              <TextInput
                value={otp}
                onChangeText={setOtp}
                placeholder="Enter OTP"
              />
              <Button title="Verify OTP" onPress={handleVerifyOTP} />
            </View>
          )}
        </View>
      );
    };
    ```
  </Tab>
</Tabs>

## Error handling

The promise rejects in three cases:

| Scenario                    | Error message                              |
| --------------------------- | ------------------------------------------ |
| User cancels authentication | `Authentication was cancelled by the user` |
| Authentication fails        | `Authentication failed: <reason>`          |
| Timeout exceeded            | `waitForAuthSuccess timed out`             |

## Related

* [Listening to events](/react-native/reference/hooks-events/events) — Subscribe to individual client events
* [Auth module events](/react-native/reference/hooks-events/events#auth-module) — Full list of auth events including `authSuccess` and `authFailed`
* [MFA](/react-native/authentication-methods/mfa/overview) — MFA flows that complete before `authSuccess` fires
