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
Complete authentication state object Show AuthenticationState properties
Whether user is currently authenticated
Whether auth state is being initialized or updated
OAuth access token (for API requests)
JWT ID token (contains user info)
Error if authentication failed
userInfo
YouVersionUserInfo | null
User information decoded from ID token Show YouVersionUserInfo properties
URL to user’s profile picture
signIn
(params?: SignInParams) => Promise<void>
Initiates OAuth sign-in flow (redirects to YouVersion) OAuth callback URL (overrides provider default)
Signs out user and clears all auth tokens
processCallback
() => Promise<SignInWithYouVersionResult | null>
Processes OAuth callback and returns user info (call on callback page)
OAuth redirect URI from provider config
Usage
Sign-In Page
Callback Page
Protected Route
With Scopes
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 >
);
}
import { useYVAuth } from '@youversion/platform-react-hooks' ;
import { useEffect , useState } from 'react' ;
import { useRouter } from 'next/router' ;
function CallbackPage () {
const { processCallback } = useYVAuth ();
const [ isProcessing , setIsProcessing ] = useState ( true );
const [ error , setError ] = useState < Error | null >( null );
const router = useRouter ();
useEffect (() => {
processCallback ()
. then ( result => {
if ( result ) {
console . log ( 'Auth success:' , result . name );
// User info is now cached, redirect to app
router . push ( '/app' );
}
})
. catch ( err => {
console . error ( 'Auth failed:' , err );
setError ( err );
})
. finally (() => {
setIsProcessing ( false );
});
}, [ processCallback , router ]);
if ( error ) {
return (
< div >
< h1 > Authentication Failed </ h1 >
< p > { error . message } </ p >
< a href = "/signin" > Try Again </ a >
</ div >
);
}
return (
< div >
{ isProcessing ? 'Processing authentication...' : 'Authentication complete' }
</ div >
);
}
import { useYVAuth } from '@youversion/platform-react-hooks' ;
import { useEffect } from 'react' ;
import { useRouter } from 'next/router' ;
function ProtectedPage () {
const { auth , userInfo , signOut } = useYVAuth ();
const router = useRouter ();
useEffect (() => {
if ( ! auth . isLoading && ! auth . isAuthenticated ) {
router . push ( '/signin' );
}
}, [ auth . isLoading , auth . isAuthenticated , router ]);
if ( auth . isLoading ) {
return < div > Loading... </ div > ;
}
if ( ! auth . isAuthenticated ) {
return null ; // Will redirect
}
return (
< div >
< h1 > Welcome, { userInfo ?. name || 'User' } ! </ h1 >
< img src = { userInfo ?. picture } alt = "Profile" />
< p > { userInfo ?. email } </ p >
< button onClick = { signOut } > Sign Out </ button >
</ div >
);
}
import { useYVAuth } from '@youversion/platform-react-hooks' ;
function SignInWithScopes () {
const { signIn } = useYVAuth ();
const handleSignIn = async () => {
await signIn ({
redirectUrl: window . location . origin + '/callback' ,
scopes: [ 'profile' , 'email' , 'highlights' ],
});
};
return (
< button onClick = { handleSignIn } >
Sign In (with highlights access)
</ button >
);
}
Authentication Flow
The authentication flow follows OAuth 2.0 with PKCE:
Step-by-Step
User clicks sign-in - App calls signIn() which redirects to YouVersion OAuth
User authorizes - User logs in and grants permissions on YouVersion
OAuth callback - YouVersion redirects back to your authRedirectUrl with auth code
Process callback - Your callback page calls processCallback() to exchange code for tokens
Cache user info - Hook decodes ID token and caches user information
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
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
Always handle loading states
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 /> ;
Process callback only once
// ✅ 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 } </> ;
}
Request only necessary scopes
// ✅ Good - requests only what's needed
await signIn ({
scopes: [ 'profile' , 'email' ],
});
// ❌ Bad - requests unnecessary permissions
await signIn ({
scopes: [ 'profile' , 'email' , 'highlights' , 'notes' , 'bookmarks' ],
});
Handle auth errors gracefully
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 >
);
}