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

# User and Session Management

Before this: create and initialize a Dynamic client (see [Creating a Dynamic Client](/javascript/reference/client/create-dynamic-client), [Initializing the Dynamic Client](/javascript/reference/client/initialize-dynamic-client)).

Here, **user** means the person using your app; **Dynamic user** is the object created after they authenticate. A user can be signed in (e.g. wallet connected) without yet having a Dynamic user. See [Signing in with a Wallet](/javascript/authentication-methods/external-wallets) for more.

## Check if signed in

What counts as "signed in" is your app's business logic, not ours. Wrap the check in a helper you own so the rule lives in one place. The minimal version is "an authenticated user exists, or any wallet is connected":

```javascript theme={"system"} theme={"system"}
import { isAnyWalletAccountConnected } from '@dynamic-labs-sdk/client';

// Your helper — extend it with whatever your app treats as "signed in".
const isSignedIn = () =>
  Boolean(dynamicClient.user) || isAnyWalletAccountConnected();

console.log(isSignedIn());
```

Most apps treat "signed in" as more than the minimal check. Add the conditions your app requires to the same helper:

* **Authenticated user** — `dynamicClient.user` is set once the user authenticates.
* **Wallet connected** — `isAnyWalletAccountConnected()` (or `getWalletAccounts()`) covers verified and unverified wallets.
* **Onboarding complete** — `isUserOnboardingComplete()` rolls up KYC fields, MFA, and recovery codes. See [Check if onboarding is complete](#check-if-onboarding-is-complete).
* **Device registered** — `isDeviceRegistrationRequired(user)`. See [Check if the user needs to complete device registration](#check-if-the-user-needs-to-complete-device-registration).
* **MFA satisfied** — `isUserMissingMfaAuth()` and `isPendingRecoveryCodesAcknowledgment()` flag MFA the user still owes.
* **Required embedded wallet** — `getChainsMissingWaasWalletAccounts()` from `@dynamic-labs-sdk/client/waas` returns the chains where the user still needs an embedded wallet.

You're also encouraged to fold in your own app-specific logic — a completed server-side session, accepted terms of service, a required plan or role — so "signed in" means exactly what your app needs, all in one helper:

```javascript theme={"system"} theme={"system"}
const isSignedIn = () =>
  Boolean(dynamicClient.user) &&
  isUserOnboardingComplete() &&
  getChainsMissingWaasWalletAccounts().length === 0 &&
  myAppHasActiveSession(); // your own logic
```

## Log the user out

Call the `logout` function, and it will clear all the session data, including the Dynamic user and any connected wallets (non verified wallets).

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={"system"} theme={"system"}
    import { logout } from '@dynamic-labs-sdk/client';

    const handleLogout = async () => {
      await logout();
    };

    // ...
    ```
  </Tab>

  <Tab title="React">
    ```tsx theme={"system"}
    import { useLogout } from '@dynamic-labs-sdk/react-hooks';

    function LogoutButton() {
      const { mutate: logout } = useLogout();
      return <button onClick={() => logout()}>Log out</button>;
    }
    ```
  </Tab>
</Tabs>

## Get the current authenticated user

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={"system"} theme={"system"}
    // If the user is authenticated, the user object will be available in the dynamicClient.user property
    const user = dynamicClient.user;
    console.log(user);
    ```
  </Tab>

  <Tab title="React">
    Use `useUser()` so your component re-renders when the user logs in or out:

    ```tsx theme={"system"}
    import { useUser } from '@dynamic-labs-sdk/react-hooks';

    function UserProfile() {
      const { data: user } = useUser(); // re-renders on userChanged

      if (!user) return <p>Not logged in</p>;
      return <p>Welcome, {user.email}</p>;
    }
    ```
  </Tab>
</Tabs>

## Get the user JWT

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={"system"} theme={"system"}
    // If the user is authenticated and you are not using cookies authentication,
    // the jwt will be available in the dynamicClient.token property
    const jwt = dynamicClient.token;
    console.log(jwt);
    ```
  </Tab>

  <Tab title="React">
    Subscribe to `tokenChanged` so your component updates when the JWT changes:

    ```tsx theme={"system"}
    import { dynamicClient } from './dynamicClient';
    import { useOnEvent } from '@dynamic-labs-sdk/react-hooks';
    import { useState } from 'react';

    function useAuthToken() {
      const [token, setToken] = useState(dynamicClient.token);

      useOnEvent({
        event: 'tokenChanged',
        listener: () => setToken(dynamicClient.token),
      });

      return token;
    }
    ```
  </Tab>
</Tabs>

## Update the current authenticated user

Call `updateUser` to update the current Dynamic user.
You can pass many user fields to the function, and it will update the user with the new values.
If any of the fields require OTP verification (like email or phone number), the function will return an `OTPVerification` object,
that you can use to check what kind of OTP verification is required (email or phone number), send the OTP to the user, and verify the OTP.

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={"system"} theme={"system"}
    import {
      sendEmailOTP,
      updateUser,
      verifyOTP
    } from '@dynamic-labs-sdk/client';

    const handleUpdateUser = async (newName, newEmail) => {
      const otpVerification = await updateUser({ name: newName, email: newEmail });
      console.log(otpVerification);

      if (!otpVerification) {
        return;
      }

      if (otpVerification?.email) {
        // This call will send the OTP to the user's email, you should then collect the OTP from the user and then call the verifyOTP function
        await sendEmailOTP({ email: newEmail });
      }
    };

    const handleVerifyOTP = async (otpVerification, otpCode) => {
      // Use the same otpVerification object that you got from the updateUser function
      await verifyOTP({ otpVerification, verificationToken: otpCode });
    };

    // ...
    ```
  </Tab>

  <Tab title="React">
    ```tsx theme={"system"}
    import { useSendEmailOTP, useUpdateUser, useVerifyOTP } from '@dynamic-labs-sdk/react-hooks';
    import { useState } from 'react';

    function EditProfileForm() {
      const [name, setName] = useState('');
      const [email, setEmail] = useState('');
      const [otp, setOtp] = useState('');

      const { mutate: updateUser, data: otpVerification, reset: resetUpdate } = useUpdateUser();
      const { mutate: sendEmailOTP } = useSendEmailOTP();
      const { mutate: verifyOTP } = useVerifyOTP();

      const handleSave = () => {
        updateUser({ name, email }, {
          onSuccess: (verification) => {
            if (verification?.email) {
              sendEmailOTP({ email });
            }
          },
        });
      };

      if (otpVerification?.email) {
        return (
          <div>
            <input value={otp} onChange={(e) => setOtp(e.target.value)} placeholder="Enter OTP" />
            <button onClick={() => verifyOTP(
              { otpVerification, verificationToken: otp },
              { onSuccess: () => resetUpdate() }
            )}>Verify</button>
          </div>
        );
      }

      return (
        <div>
          <input value={name} onChange={(e) => setName(e.target.value)} placeholder="Name" />
          <input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" />
          <button onClick={handleSave}>Save</button>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

## Check if a user has missing fields

You can toggle user data collected and also to be required or not in the [Dynamic dashboard](https://app.dynamic.xyz/dashboard/log-in-user-profile).
We don't control that in the JavaScript SDK, but you can check if a user has missing fields by calling the `user.missingFields` property.
With that, you can display the appropriate UI to the user to complete the onboarding process, and call the `updateUser` function to update the user with the missing fields.

```javascript theme={"system"} theme={"system"}

const onUserAuthenticated = async () => {
  const { missingFields } = dynamicClient.user;

  if (!missingFields.length) {
    // User has no missing fields
    return;
  }

  missingFields.forEach((field) => {
    console.log(`Name : ${field.name}`);
    // If you just want to know the required fields, you can check the field.required property
    console.log(`Required : ${field.required}`);
    console.log(`Type : ${field.type}`);
    // You can check if OTP verification is required for this field by checking the field.verification property
    console.log(`Type : ${field.verification}`);
  });
};

// ...

```

## Check if onboarding is complete

You can check if a user has completed all onboarding requirements (including KYC fields, MFA authentication, and recovery codes acknowledgment) by calling the `isUserOnboardingComplete` function.
This function provides a comprehensive check of all requirements and returns `true` only when the user has completed everything.

```javascript theme={"system"} theme={"system"}
import { isUserOnboardingComplete } from '@dynamic-labs-sdk/client';

const onUserAuthenticated = () => {
  const isComplete = isUserOnboardingComplete();

  if (!isComplete) {
    // User has pending onboarding requirements
    // You can check individual requirements using:
    // - user.missingFields for KYC fields
    // - isUserMissingMfaAuth() for MFA authentication
    // - isPendingRecoveryCodesAcknowledgment() for recovery codes
    redirectToOnboarding();
  } else {
    // User has completed all requirements
    redirectToDashboard();
  }
};

// ...

```

See the [isUserOnboardingComplete](/javascript/authentication-methods/is-user-onboarding-complete) documentation for more details on how to use this function and check individual requirements.

## Check if the user needs to complete device registration

After authentication, you can check whether the current device needs to be registered and complete registration on redirect. For the full flow, see [Device Registration](/javascript/authentication-methods/device-registration).

```javascript theme={"system"} theme={"system"}
import {
  completeDeviceRegistration,
  detectDeviceRegistrationRedirect,
  getDeviceRegistrationTokenFromUrl,
  isDeviceRegistrationRequired,
} from '@dynamic-labs-sdk/client';

const user = dynamicClient.user;

if (user && isDeviceRegistrationRequired(user)) {
  // Show UI telling the user to verify their device from the email link
}

const completeRegistrationIfNeeded = async () => {
  const url = window.location.href;

  if (detectDeviceRegistrationRedirect({ url })) {
    const deviceToken = getDeviceRegistrationTokenFromUrl({ url });
    await completeDeviceRegistration({ deviceToken });
  }
};


```

## Refreshing the current authenticated user (Dynamic user)

You can refresh the current authenticated user (Dynamic user) by calling the `refreshUser` function.
This function will refresh the user object in the SDK with the latest data from the server.

```javascript theme={"system"} theme={"system"}
import { refreshUser } from '@dynamic-labs-sdk/client';

const handleRefreshUser = async () => {
  await refreshUser();
};

// ...

```
