Summary

A hook which can be used to trigger sign-in with social or social account linking and unlinking for an authenticated user. The hook needs to be initialized within a child of DynamicContextProvider.

Usage

The hook can receive an optional sessionTimeout param that is used to cancel sign-in/linking due to inactivity. It’s value should be a number (time in milliseconds) and defaults to 10s (10000 ms).

Note: This is mainly used for X/Twitter oauth, since we cannot detect when the oauth window is closed for this provider.

Example setting timeout to 20s:

  const {
    signInWithSocialAccount,
    isProcessing,
    error,
  } = useSocialAccounts({sessionTimeout: 20000});

Available functions and states:

MethodTypeDescription
errorSocialOAuthError | undefinedContains the code and message in case of an error during the link or unlink process
getLinkedAccountInformation(provider: ProviderEnum) => SocialAccountInformationReturns an object with the information about the linked account for the specified provider if there’s a linked account. If not, returns undefined.
isLinked(provider: ProviderEnum) => booleanReturns true if user has an account linked for the specified provider. Otherwise returns false.
isProcessingbooleanIndicates whether a link or unlink request is in process
linkSocialAccount(provider: ProviderEnum) => Promise<void>When called, will trigger the oauth linking for the specified provider
signInWithSocialAccount(provider: ProviderEnum) => Promise<void>When called, will trigger the oauth sign-in for the specified provider
unlinkSocialAccount(provider: ProviderEnum) => Promise<void>When called, it will unlink the user account for the specified provider

Types

ProviderEnum =
  "discord" |
  "facebook" |
  "farcaster" |
  "github" |
  "google" |
  "instagram" |
  "twitch" |
  "twitter";
SocialAccountInformation = {
  id: string;
  provider: ProviderEnum;
  accountId: string;
  publicIdentifier: string;
  avatar?: string;
  displayName?: string;
  email?: string;
  username?: string;
};
SocialOAuthErrorCode =
  "account_already_linked" | // trying to link an account for a provider that already has an account linked
  "account_already_linked_to_different_profile" | //trying to link an account that is already linked to a different user
  "invalid_provider" | // the provider is not a valid social provider
  "no_account_linked" | // trying to unlink the account for a provider that has no linked accounts
  "no_auth_code" | // oauth provider did not return a valid authorization code
  "no_oauth_url" | // could not find the oauth url to initiate linking flow
  "no_provider" | // a hook menthod was called without passing a provider when required
  "oauth_error" | // user denied access to account
  "oauth_window_timeout" | // user closed oauth window or left if open for too long without finishing auth flow
  "provider_not_enabled" | // the provider has not been enabled in the dashboard for the social account linking feature
  "session_timeout" | // user tried to authorize oauth after the timeout period
  "signin_error" | // could not sign-in with social account
  "social_linking_not_enabled" | // the social account linking feature has not been enabled in the dashboard so it cannot be used
  "unlink_error" | // could not unlink social account
  "verification_error" | // could not validate authorization code
  "general_error";

Linking/unlinking example

import {
  useSocialAccounts,
} from '@dynamic-labs/sdk-react-core';
import { ProviderEnum } from '@dynamic-labs/types';
import { GoogleIcon } from '@dynamic-labs/iconic';

const UserProfileSocialAccount = () => {
  const {
    linkSocialAccount,
    unlinkSocialAccount,
    isProcessing,
    isLinked,
    getLinkedAccountInformation,
  } = useSocialAccounts();

  const provider = ProviderEnum.Google;
  const isGoogleLinked = isLinked(provider);
  const connectedAccountInfo = getLinkedAccountInformation(provider);

  return (
    <div>
      <div className="icon">
        {isGoogleLinked ? (
          <Avatar avatarUrl={connectedAccountInfo?.avatar} />
        ) : (
          <GoogleIcon />
        )}
      </div>
      <div className="label">
        <Typography>
          {connectedAccountInfo?.publicIdentifier ?? provider}
        </Typography>
      </div>
      {isGoogleLinked ? (
        <Button
          onClick={() => unlinkSocialAccount(provider)}
          loading={isProcessing}
        >
          Disconnect
        </Button>
      ) : (
        <Button
          onClick={() => linkSocialAccount(provider)}
          loading={isProcessing}
        >
          Connect
        </Button>
      )}
    </div>
  );
};

Sign-in example

import { FC } from 'react';
import {
  DynamicWidget,
  useDynamicContext,
  useSocialAccounts,
} from '@dynamic-labs/sdk-react-core';
import { ProviderEnum } from '@dynamic-labs/types';
import { FarcasterIcon, GoogleIcon, TwitterIcon } from '@dynamic-labs/iconic';

const SocialSignIn = () => {
  const { error, isProcessing, signInWithSocialAccount } = useSocialAccounts();

  return (
    <div className='headless-social-signin'>
      <div className='headless-social-signin__container'>
        <p>Log in or sign up</p>

        <button onClick={() => signInWithSocialAccount(ProviderEnum.Farcaster)}>
          <FarcasterIcon />
          Sign in with Farcaster
        </button>
        <button onClick={() => signInWithSocialAccount(ProviderEnum.Google)}>
          <GoogleIcon />
          Sign in with Google
        </button>
        <button onClick={() => signInWithSocialAccount(ProviderEnum.Twitter)}>
          <TwitterIcon />
          Sign in with Twitter
        </button>
        {isProcessing && <span className='processing'>Processing...</span>}
        {error && <span className='error'>{error.message}</span>}
      </div>
    </div>
  );
};

const LoggedInUser = () => {
  const { user } = useDynamicContext();

  return (
    <>
      <DynamicWidget />
      <p>user: {user?.email}</p>
    </>
  );
};

export const HeadlessSocialSignInView: FC = () => {
  const { user } = useDynamicContext();

  return (
    <div style={{ overflowY: 'scroll' }}>
      {user ? <LoggedInUser /> : <SocialSignIn />}
    </div>
  );
};