Skip to main content
Authentication hooks provide OAuth-based user authentication with YouVersion. They handle sign-in, callback processing, and session management.

useYVAuth

Comprehensive authentication hook that provides complete auth functionality including sign-in, sign-out, callback processing, and user info.
Requires YouVersionProvider with includeAuth={true} and authRedirectUrl configured.

Returns

auth
AuthenticationState
Complete authentication state object
userInfo
YouVersionUserInfo | null
User information decoded from ID token
signIn
(params?: SignInParams) => Promise<void>
Initiates OAuth sign-in flow (redirects to YouVersion)
signOut
() => void
Signs out user and clears all auth tokens
processCallback
() => Promise<SignInWithYouVersionResult | null>
Processes OAuth callback and returns user info (call on callback page)
redirectUri
string | undefined
OAuth redirect URI from provider config

Usage

import { useYVAuth } from '@youversion/platform-react-hooks';

function SignInPage() {
  const { auth, signIn } = useYVAuth();

  const handleSignIn = async () => {
    try {
      await signIn({
        redirectUrl: window.location.origin + '/callback',
      });
    } catch (error) {
      console.error('Sign in failed:', error);
    }
  };

  if (auth.isLoading) {
    return <div>Checking authentication...</div>;
  }

  if (auth.isAuthenticated) {
    return <div>Already signed in!</div>;
  }

  return (
    <div>
      <h1>Sign In</h1>
      <button onClick={handleSignIn} disabled={auth.isLoading}>
        {auth.isLoading ? 'Signing in...' : 'Sign In with YouVersion'}
      </button>
    </div>
  );
}

Authentication Flow

The authentication flow follows OAuth 2.0 with PKCE:

Step-by-Step

  1. User clicks sign-in - App calls signIn() which redirects to YouVersion OAuth
  2. User authorizes - User logs in and grants permissions on YouVersion
  3. OAuth callback - YouVersion redirects back to your authRedirectUrl with auth code
  4. Process callback - Your callback page calls processCallback() to exchange code for tokens
  5. Cache user info - Hook decodes ID token and caches user information
  6. Access protected resources - User info is now available via userInfo, and tokens are stored for API requests

useTheme

Accesses the current theme from YouVersionProvider.

Returns

theme
'light' | 'dark'
Current theme (resolved from provider, never returns ‘system’)

Usage

import { useTheme } from '@youversion/platform-react-hooks';

function ThemedComponent() {
  const theme = useTheme();
  
  return (
    <div className={theme === 'dark' ? 'dark-mode' : 'light-mode'}>
      Current theme: {theme}
    </div>
  );
}

Authentication Types

AuthenticationState

interface AuthenticationState {
  isAuthenticated: boolean;
  isLoading: boolean;
  accessToken: string | null;
  idToken: string | null;
  result: SignInWithYouVersionResult | null;
  error: Error | null;
}

YouVersionUserInfo

interface YouVersionUserInfo {
  sub: string;        // User ID
  name: string;       // Display name
  email: string;      // Email address
  picture: string;    // Profile picture URL
  email_verified?: boolean;
}

AuthenticationScopes

type AuthenticationScopes = 
  | 'profile'
  | 'email'
  | 'highlights'
  | 'notes'
  | 'bookmarks';

Best Practices

const { auth, userInfo } = useYVAuth();

// ✅ Good - handles all states
if (auth.isLoading) return <Spinner />;
if (!auth.isAuthenticated) return <SignInPrompt />;
return <UserProfile user={userInfo} />;

// ❌ Bad - doesn't handle loading
return auth.isAuthenticated ? <UserProfile /> : <SignInPrompt />;
// ✅ Good - processes once on mount
useEffect(() => {
  processCallback().then(/* ... */);
}, [processCallback]);

// ❌ Bad - could process multiple times
processCallback(); // Don't call outside useEffect
function ProtectedRoute({ children }) {
  const { auth } = useYVAuth();
  const router = useRouter();
  
  useEffect(() => {
    if (!auth.isLoading && !auth.isAuthenticated) {
      router.push('/signin');
    }
  }, [auth.isLoading, auth.isAuthenticated]);
  
  if (!auth.isAuthenticated) return null;
  
  return <>{children}</>;
}
// ✅ Good - requests only what's needed
await signIn({
  scopes: ['profile', 'email'],
});

// ❌ Bad - requests unnecessary permissions
await signIn({
  scopes: ['profile', 'email', 'highlights', 'notes', 'bookmarks'],
});
const { auth } = useYVAuth();

if (auth.error) {
  return (
    <ErrorBoundary>
      <p>Authentication error: {auth.error.message}</p>
      <button onClick={() => window.location.href = '/signin'}>
        Try Again
      </button>
    </ErrorBoundary>
  );
}

Build docs developers (and LLMs) love