> ## 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.

# Users

> The React SDK exposed the user through useDynamicContext() and rendered the profile, settings, and delete screens inside DynamicUserProfile. In the JavaScript SDK you read the user with useUser() and build those screens yourself.

The React SDK kept the authenticated user on `useDynamicContext()`, exposed a `useIsLoggedIn()` flag, and rendered the profile, settings, and account-deletion screens inside the `DynamicUserProfile` widget. The JavaScript SDK gives you the same user data through `useUser()` (and `getDefaultClient().user`), a set of focused functions for updating and deleting the account, and leaves every screen to you.

Building the profile, settings, and delete screens is the same in any JavaScript SDK app, so it isn't repeated here: [**User profile & settings** (Building UI)](/docs/javascript/building-ui/user-profile-settings) covers reading, updating, and deleting with full code. This page is the React→JavaScript translation plus the migration-specific behavior.

## Reading the user

| React SDK                  | JavaScript SDK                                                  |
| -------------------------- | --------------------------------------------------------------- |
| `useDynamicContext().user` | `useUser()` / `getDefaultClient().user`                         |
| `useIsLoggedIn()`          | No single flag — see the note below the table                   |
| session expiry             | `useSessionExpiresAt()` / `getDefaultClient().sessionExpiresAt` |
| `getAuthToken()`           | `getDefaultClient().token`                                      |

* **No `isLoggedIn` boolean — you define what "signed in" means.** There's no single flag anymore; your app decides the condition and composes it from SDK helpers: whether a user exists (`useUser()` / `getDefaultClient().user` returns the `User` or `null`), whether a wallet is connected (`isAnyWalletAccountConnected()`), and so on. In vanilla JS, recompute it on the `userChanged` event (via [`onEvent`](/docs/javascript/reference/client/on-event) — see the [events catalog](/docs/javascript/reference/client/events-catalog)).
* **Reading the JWT directly isn't recommended.** `getDefaultClient().token` is the current JWT or `null`, but prefer letting the SDK attach auth to your requests rather than reading the token yourself. In cookie-based environments the token lives in an httpOnly cookie and is never exposed, so `token` is always `null` — send credentialed requests instead (see the Cookies guide).

## Updating, refreshing, deleting

| React SDK                               | JavaScript SDK                       |
| --------------------------------------- | ------------------------------------ |
| `useUserUpdateRequest()`                | `updateUser()` / `useUpdateUser()`   |
| `useRefreshUser()` / `useRefreshAuth()` | `refreshAuth()` / `useRefreshAuth()` |
| `useDeleteUserAccount()`                | `deleteUser()` / `useDeleteUser()`   |
| `useDynamicContext().handleLogOut`      | `logout()` / `useLogout()`           |

* **`updateUser({ userFields })` can return a verification.** When the change touches a contact method that needs re-verification (email or phone), it resolves with an `OTPVerification` object instead of applying immediately — prompt for the code and complete verification before treating the change as saved. Other fields (`firstName`, `username`, `metadata`, …) apply directly. [**User profile & settings** (Building UI)](/docs/javascript/building-ui/user-profile-settings#updating-profile-fields) shows the returned object's shape and how to tell whether the code went to the email or the phone (`otpVerification.email` vs `otpVerification.phoneNumber`).
* **`refreshAuth()` refetches the user and rotates the session token** in one call — use it after a server-side change or to extend a session (see [Refresh auth](/docs/javascript/authentication-methods/refresh-auth)).
* **`deleteUser()` has no confirmation UI.** It permanently removes the account, so build your own "are you sure?" step before calling it.

## Verified credentials and login methods

The `User` carries a `verifiedCredentials` array — the same structure as the React SDK. Each credential has a `format` (a few examples: `'email'`, `'phoneNumber'`, `'oauth'`, `'blockchain'`, `'passkey'`, `'externalUser'`, `'totp'`) telling you how the user proved that identifier, so you distinguish login methods by reading `format` rather than a dedicated flag. For the full set of formats and how to read them — including `lastVerifiedCredentialId` for the most recent login — see [**Distinguishing login methods**](/docs/javascript/reference/client/distinguishing-login-methods).

## Authorization

* **Gate on `checkUserScopes({ scopes, user })`** — it returns whether the user was granted every scope you pass (see [Token scopes](/docs/javascript/reference/client/jwt-scopes) for the available scopes). The React SDK's `AccessBlockedView` / `NoAccess` screens are gone; render your own blocked state when the check fails.
* **Linked social accounts** are read with `getUserSocialAccounts()` / `useGetUserSocialAccounts()` and detached with `unlinkSocialAccount()`. `unlinkSocialAccount()` requires a `Credentialunlink` elevated access token with no fallback — see [Social account linking](/docs/javascript/migrating-from-react/non-wallet-authentication#social-account-linking) for the `checkStepUpAuth()` pattern.

## What you now build

The `DynamicUserProfile` widget rendered these; in the JavaScript SDK they are yours:

* **Profile & settings screens** — the form that edits `userFields` and calls `updateUser()`. Follow [**User profile & settings** (Building UI)](/docs/javascript/building-ui/user-profile-settings) for the full flow.
* **Account deletion** — the confirmation dialog that gates [`deleteUser()`](/docs/javascript/reference/client/delete-user).
* **Access-blocked screen** — what to show when [`checkUserScopes()`](/docs/javascript/reference/client/jwt-scopes) fails.
* **Connected apps** — the list of linked social accounts with unlink controls, built on [social linking](/docs/javascript/authentication-methods/social-linking).

## Errors you now own

| Situation                           | What to do                                                                                          |
| ----------------------------------- | --------------------------------------------------------------------------------------------------- |
| `updateUser` returns a verification | The email/phone change is pending — prompt for the OTP and complete it before showing success.      |
| `updateUser` rejects                | Keep the form open with the entered values and surface a retry; nothing was saved.                  |
| `deleteUser` rejects                | The account still exists — surface the failure and leave the user signed in.                        |
| Reading `token` returns `null`      | Either nobody is signed in, or you're in a cookie environment — send credentialed requests instead. |

## See also

* [User profile & settings (Building UI)](/docs/javascript/building-ui/user-profile-settings) — build the profile and settings screens
* [Handling blocked wallets (Building UI)](/docs/javascript/building-ui/blocked-wallet-screening) — build the access-blocked experience
* [Basic setup](/docs/javascript/migrating-from-react/basic-setup) — the client, provider, and events → promises shift
* [Post-login user setup](/docs/javascript/migrating-from-react/post-login-user-setup) — get a freshly authenticated user ready for your app
* Cookies — cookie-based sessions and why `token` is `null`
