signOut
The signOut method signs out the current user by clearing all stored authentication data and redirecting to a specified URL. It ensures complete cleanup of the authentication state.
This method is accessed via authClient.signOut() and provides a clean way to log users out of your application.
Method Signature
signOut(redirectUri?: string): void
Parameters
redirectUri
- type:
string(optional)- URL to redirect to after sign out
- Default:
'/'(homepage)
Return Value
Returns void. The method performs its operations synchronously and redirects immediately.
How It Works
- Clears localStorage - Removes the
vuer_tokenkey containing access and refresh tokens - Clears sessionStorage - Removes all PKCE parameters (
pkce_state,pkce_verifier,vuer_callback_url) - Redirects the page - Navigates to the specified URL (default: homepage)
Usage
Basic Sign Out
import { authClient } from "@/auth";
function SignOutButton() {
return (
<button onClick={() => authClient.signOut()}>
Sign Out
</button>
);
}
Sign Out with Custom Redirect
import { authClient } from "@/auth";
function SignOutButton() {
const handleSignOut = () => {
// Redirect to login page after sign out
authClient.signOut("/login");
};
return <button onClick={handleSignOut}>Sign Out</button>;
}
Sign Out with Confirmation
import { authClient } from "@/auth";
function SignOutButton() {
const handleSignOut = () => {
if (confirm("Are you sure you want to sign out?")) {
authClient.signOut();
}
};
return <button onClick={handleSignOut}>Sign Out</button>;
}
Sign Out from Navigation Menu
import { authClient } from "@/auth";
function UserMenu() {
const { user, isAuthenticated } = authClient.useAuth();
if (!isAuthenticated || !user) return null;
return (
<div className="user-menu">
<img src={user.picture} alt={user.name} />
<span>{user.name}</span>
<button onClick={() => authClient.signOut()}>
Sign Out
</button>
</div>
);
}
Sign Out with Loading State
import { authClient } from "@/auth";
import { useState } from "react";
function SignOutButton() {
const [isSigningOut, setIsSigningOut] = useState(false);
const handleSignOut = async () => {
setIsSigningOut(true);
// Optional: Call backend to invalidate server-side session
try {
await fetch("/api/logout", {
method: "POST",
headers: {
Authorization: `Bearer ${authClient.token()?.access_token}`,
},
});
} catch (error) {
console.error("Failed to invalidate server session:", error);
}
// Sign out client-side
authClient.signOut();
};
return (
<button onClick={handleSignOut} disabled={isSigningOut}>
{isSigningOut ? "Signing out..." : "Sign Out"}
</button>
);
}
Sign Out from Multiple Locations
import { authClient } from "@/auth";
function Header() {
return (
<header>
<button onClick={() => authClient.signOut()}>Sign Out</button>
</header>
);
}
function ProfilePage() {
return (
<div>
<h1>Profile</h1>
<button onClick={() => authClient.signOut("/login")}>
Sign Out
</button>
</div>
);
}
Complete Sign Out Flow
For a complete sign out that includes server-side cleanup:
import { authClient } from "@/auth";
async function completeSignOut() {
try {
// 1. Optional: Revoke refresh token on server
const token = authClient.token();
if (token?.refresh_token) {
await fetch("/api/auth/revoke", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token.access_token}`,
},
body: JSON.stringify({
token: token.refresh_token,
token_type_hint: "refresh_token",
}),
});
}
} catch (error) {
console.error("Failed to revoke token:", error);
// Continue with client-side sign out even if server revocation fails
}
// 2. Clear client-side state and redirect
authClient.signOut("/login");
}
function SignOutButton() {
return <button onClick={completeSignOut}>Sign Out</button>;
}
What Gets Cleared
localStorage
vuer_token- Access token, refresh token, ID token, and metadata
sessionStorage
pkce_state- PKCE state parameterpkce_verifier- PKCE code verifiervuer_callback_url- Stored callback URL
In-Memory State
- Cached token (cleared implicitly when localStorage is cleared)
- Zustand store state (user info, loading states)
Redirect Behavior
After sign out, the page is redirected using window.location.href:
// Default behavior
authClient.signOut(); // Redirects to '/'
// Custom redirect
authClient.signOut("/login"); // Redirects to '/login'
authClient.signOut("/goodbye"); // Redirects to '/goodbye'
The redirect is immediate and synchronous, so any code after signOut() will not execute:
// ❌ This won't work
authClient.signOut();
console.log("This will never execute");
// ✅ Do cleanup before sign out
console.log("Signing out...");
authClient.signOut();
Common Patterns
Sign Out on Token Expiration
import { authClient } from "@/auth";
import { useEffect } from "react";
function TokenExpirationHandler() {
useEffect(() => {
const checkTokenExpiration = () => {
const token = authClient.token();
if (token) {
const expiresAt = Date.now() + token.expires_in * 1000;
const isExpired = Date.now() >= expiresAt;
if (isExpired) {
alert("Your session has expired. Please sign in again.");
authClient.signOut("/login");
}
}
};
const interval = setInterval(checkTokenExpiration, 60000); // Check every minute
return () => clearInterval(interval);
}, []);
return null;
}
Sign Out on 401 Error
import { authClient } from "@/auth";
async function fetchWithAutoSignOut(url: string) {
const response = await authClient.$fetch(url);
if (response.status === 401) {
alert("Your session has expired. Please sign in again.");
authClient.signOut("/login");
return null;
}
return response;
}
Sign Out All Tabs
import { authClient } from "@/auth";
import { useEffect } from "react";
function GlobalSignOutHandler() {
useEffect(() => {
const handleStorageChange = (e: StorageEvent) => {
// If token was removed in another tab, sign out in this tab too
if (e.key === "vuer_token" && e.newValue === null) {
window.location.href = "/login";
}
};
window.addEventListener("storage", handleStorageChange);
return () => window.removeEventListener("storage", handleStorageChange);
}, []);
return null;
}
Security Considerations
-
Client-Side Only
signOut()only clears client-side data- For complete security, also invalidate the session on your backend
- Consider revoking refresh tokens on the auth server
-
No Server Communication
- By default, no request is made to the server
- Server-side sessions or tokens remain valid until they expire
- Implement server-side sign out if needed
-
Immediate Effect
- All authentication data is cleared immediately
- The redirect prevents any further code execution
- User cannot access protected resources after sign out
Troubleshooting
User still appears signed in after sign out:
- Check if using proper storage keys
- Verify localStorage is not disabled
- Check for browser extensions that might cache data
Redirect doesn't work:
- Ensure the URL is valid and accessible
- Check for JavaScript errors that might prevent redirect
- Verify no other code is preventing navigation
Sign out doesn't clear all data:
- The method only clears vuer-auth-specific keys
- Application-specific data should be cleared separately
- Consider implementing a custom sign out function for complete cleanup
See Also
- signIn function - Sign in the user
- useAuth hook - Hook with built-in signOut method
- token function - Access stored tokens