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

# Non-wallet authentication

> Migrate email, SMS, social, passkey, and external-JWT sign-in from the React SDK to the JavaScript SDK.

Non-wallet auth methods carry over, but each becomes an explicit call (or pair of calls) instead of a context that manages the flow for you. This page maps each React SDK API to its JavaScript SDK equivalent and links to the full implementation guide for each.

## Email & SMS OTP

The React SDK's `useConnectWithOtp` bundled sending and verifying. In the JavaScript SDK these are two explicit steps: send the code, then verify it. Sending returns an `otpVerification` handle that you pass to `verifyOTP`.

| React SDK | JavaScript SDK |
| - | - |
| `useConnectWithOtp().connectWithEmail` | `sendEmailOTP()` / `useSendEmailOTP()` |
| `useConnectWithOtp().connectWithSms` | `sendSmsOTP()` / `useSendSmsOTP()` |
| `useConnectWithOtp().verifyOneTimePassword` | `verifyOTP()` / `useVerifyOTP()` |

> [tab] TypeScript
>
> ```typescript theme={"system"}
> import { sendEmailOTP, verifyOTP } from '@dynamic-labs-sdk/client';
>
> const otpVerification = await sendEmailOTP({ email });
> const user = await verifyOTP({ otpVerification, verificationToken: codeFromUser });
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useSendEmailOTP, useVerifyOTP } from '@dynamic-labs-sdk/react-hooks';
>
> const { mutateAsync: sendEmailOTP } = useSendEmailOTP();
> const { mutateAsync: verifyOTP } = useVerifyOTP();
>
> const otpVerification = await sendEmailOTP({ email });
> const user = await verifyOTP({ otpVerification, verificationToken: codeFromUser });
> ```

For the full two-step UI (resend, error handling, SMS variant), see [Email & SMS OTP sign-in](https://docs.dynamic.xyz/docs/javascript/building-ui/email-sms-otp-sign-in.md).

## Social sign-in & OAuth redirect

> [!WARNING]
>
> **This is the change most likely to break a migration.** In the React SDK, OAuth redirect detection was automatic — the SDK inspected the URL on mount and completed sign-in for you. In the JavaScript SDK, **you must complete the redirect yourself** on every app load, or returning users never finish signing in.

Start sign-in with `signInWithSocialRedirect`, then on the page the provider returns to, detect and complete the callback.

| React SDK | JavaScript SDK |
| - | - |
| `useSocialAccounts().signInWithSocialAccount` | `signInWithSocialRedirect()` / `useSignInWithSocialRedirect()` |
| automatic redirect detection | `detectSocialRedirectUrl()` + `completeSocialRedirect()` on load / `useDetectSocialRedirectUrl()` + `useCompleteSocialRedirect()` |

> [tab] TypeScript
>
> ```typescript theme={"system"}
> import {
>   detectSocialRedirectUrl,
>   completeSocialRedirect,
>   clearSocialRedirectParams,
> } from '@dynamic-labs-sdk/client';
>
> const url = new URL(window.location.href);
>
> if (await detectSocialRedirectUrl({ url })) {
>   await completeSocialRedirect({ url });
>   clearSocialRedirectParams();
> }
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useEffect } from 'react';
> import { clearSocialRedirectParams } from '@dynamic-labs-sdk/client';
> import {
>   useDetectSocialRedirectUrl,
>   useCompleteSocialRedirect,
> } from '@dynamic-labs-sdk/react-hooks';
>
> export function CompleteSocialSignIn() {
>   const url = new URL(window.location.href);
>   const { data: isReturningFromProvider } = useDetectSocialRedirectUrl({ url });
>   const { mutateAsync: completeSocialRedirect } = useCompleteSocialRedirect();
>
>   useEffect(() => {
>     if (isReturningFromProvider) {
>       void completeSocialRedirect({ url }).then(() => {
>         clearSocialRedirectParams();
>       });
>     }
>   }, [isReturningFromProvider]);
>
>   return null;
> }
> ```

For sign-in buttons and the complete redirect handler, see [Social sign-in & OAuth redirect handling](https://docs.dynamic.xyz/docs/javascript/building-ui/social-oauth-redirect-handling.md).

## Passkeys

Passkey sign-in keeps the same hook name. Registration is a separate explicit call.

| React SDK | JavaScript SDK |
| - | - |
| `useSignInWithPasskey()` | `signInWithPasskey()` / `useSignInWithPasskey()` |
| passkey registration (via sync flow) | `registerPasskey()` / `useRegisterPasskey()` |

> [!WARNING]
>
> `registerPasskey()` requests a `Credentiallink` elevated access token the same way `registerTotpMfaDevice()` does (see [Registering or removing a device needs an elevated token](https://docs.dynamic.xyz/docs/javascript/migrating-from-react/mfa.md#registering-or-removing-a-device-needs-an-elevated-token)) — expect it to need a `checkStepUpAuth({ scope: TokenScope.Credentiallink })` check beforehand if the user doesn't already hold one.

For sign-in and registration UI, see [Passkey sign-in & registration](https://docs.dynamic.xyz/docs/javascript/building-ui/passkey-sign-in-registration.md).

## External JWT

If you authenticate the user elsewhere and hand Dynamic a JWT, the hook is renamed but the shape is the same.

| React SDK | JavaScript SDK |
| - | - |
| `useExternalAuth()` | `signInWithExternalJwt()` / `useSignInWithExternalJwt()` |

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

const user = await signInWithExternalJwt({ externalJwt });
```

This flow is essentially headless — you already authenticated the user, so there's no dedicated Building UI page.

## Social account linking

Managing already-linked social accounts moves from one hook to focused functions.

| React SDK | JavaScript SDK |
| - | - |
| `useSocialAccounts()` (linked accounts) | `getUserSocialAccounts()` / `useGetUserSocialAccounts()` |
| `useSocialAccounts().unlinkSocialAccount` | `unlinkSocialAccount()` / `useUnlinkSocialAccount()` |

> [!WARNING]
>
> `unlinkSocialAccount()` requires a `Credentialunlink` elevated access token — there's no legacy fallback, so it 403s (`Elevated access token required`) if you call it directly. Check with `checkStepUpAuth({ scope: TokenScope.Credentialunlink })` first and, if required, re-verify the user with an existing credential (email OTP, TOTP, passkey, or a connected wallet), passing `requestedScopes: [TokenScope.Credentialunlink]` on that call. See [Registering or removing a device needs an elevated token](https://docs.dynamic.xyz/docs/javascript/migrating-from-react/mfa.md#registering-or-removing-a-device-needs-an-elevated-token) for the full pattern — it's the same mechanism.

> [tab] TypeScript
>
> ```typescript theme={"system"}
> import {
>   checkStepUpAuth,
>   sendEmailOTP,
>   verifyOTP,
>   unlinkSocialAccount,
>   TokenScope,
> } from '@dynamic-labs-sdk/client';
>
> async function unlink(verifiedCredentialId: string) {
>   const { isRequired } = await checkStepUpAuth({
>     scope: TokenScope.Credentialunlink,
>   });
>
>   if (isRequired) {
>     // Re-verify with an existing credential — email OTP shown here.
>     const otpVerification = await sendEmailOTP({ email });
>     const code = await promptForCode(); // your implementation
>     await verifyOTP({
>       otpVerification,
>       verificationToken: code,
>       requestedScopes: [TokenScope.Credentialunlink],
>     });
>   }
>
>   // The elevated token from above is picked up automatically.
>   await unlinkSocialAccount({ verifiedCredentialId });
> }
> ```

Linked-account management typically lives in your profile UI — see [User profile & settings](https://docs.dynamic.xyz/docs/javascript/building-ui/user-profile-settings.md).

## After any method

Signing in no longer runs onboarding, MFA, device registration, or wallet creation for you. Run those steps yourself once auth resolves — see [Post-login user setup](https://docs.dynamic.xyz/docs/javascript/building-ui/post-auth-user-setup.md).

## See also

* [Email & SMS OTP sign-in](https://docs.dynamic.xyz/docs/javascript/building-ui/email-sms-otp-sign-in.md)
* [Social sign-in & OAuth redirect handling](https://docs.dynamic.xyz/docs/javascript/building-ui/social-oauth-redirect-handling.md)
* [Passkey sign-in & registration](https://docs.dynamic.xyz/docs/javascript/building-ui/passkey-sign-in-registration.md)
* [Wallet authentication](https://docs.dynamic.xyz/docs/javascript/migrating-from-react/wallet-authentication.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.