refreshToken

The refreshToken method obtains a new access token using the refresh token. This is used when the current access token has expired but the refresh token is still valid.

This method is accessed via authClient.refreshToken() and automatically updates the stored tokens with the new values.


Method Signature

refreshToken(): Promise<Token | null>

Parameters

This method doesn't accept any parameters. It automatically uses the refresh token stored in localStorage.


Return Value

Returns Promise<Token | null>:

  • Token object containing the new access token and related data if successful
  • null if there's no refresh token available or the refresh fails

Token Object Structure

interface Token {
  access_token: string;     // New access token for API requests
  refresh_token: string;    // New or same refresh token
  id_token: string;         // New ID token (JWT) with user claims
  token_type: string;       // Token type (usually "Bearer")
  expires_in: number;       // Expiration time in seconds
  scope: string;            // Space-separated granted scopes
}

How It Works

  1. Retrieves the current refresh token from localStorage
  2. Makes a POST request to /api/auth/oauth2/token with grant_type=refresh_token
  3. Receives new tokens from the server
  4. Updates localStorage with the new token set
  5. Returns the new token object

Usage

Basic Usage

import { authClient } from "@/auth";

async function refreshAccessToken() {
  const newToken = await authClient.refreshToken();

  if (newToken) {
    console.log("Token refreshed successfully");
    console.log("New access token:", newToken.access_token);
  } else {
    console.log("Failed to refresh token");
  }
}

Automatic Token Refresh

Implement automatic token refresh before expiration:

import { authClient } from "@/auth";
import { useEffect } from "react";

function TokenRefreshManager() {
  useEffect(() => {
    const checkAndRefreshToken = async () => {
      const token = authClient.token();

      if (!token) return;

      // Calculate time until token expires
      const expiresAt = Date.now() + token.expires_in * 1000;
      const timeUntilExpiry = expiresAt - Date.now();

      // Refresh if less than 5 minutes remaining
      if (timeUntilExpiry < 5 * 60 * 1000) {
        console.log("Token expiring soon, refreshing...");
        await authClient.refreshToken();
      }
    };

    // Check every minute
    const interval = setInterval(checkAndRefreshToken, 60 * 1000);

    // Check immediately on mount
    checkAndRefreshToken();

    return () => clearInterval(interval);
  }, []);

  return null;
}

// Use in your app
function App() {
  return (
    <>
      <TokenRefreshManager />
      {/* Rest of your app */}
    </>
  );
}

Refresh on API Error

Retry failed API requests after refreshing the token:

import { authClient } from "@/auth";

async function fetchWithTokenRefresh(url: string) {
  try {
    // Try the request with current token
    const response = await authClient.$fetch(url);

    if (!response.ok && response.status === 401) {
      // Token expired, try to refresh
      console.log("Token expired, refreshing...");
      const newToken = await authClient.refreshToken();

      if (newToken) {
        // Retry the request with new token
        return await authClient.$fetch(url);
      } else {
        throw new Error("Failed to refresh token");
      }
    }

    return response;
  } catch (error) {
    console.error("Request failed:", error);
    throw error;
  }
}

With User Feedback

import { authClient } from "@/auth";
import { useState } from "react";

function RefreshTokenButton() {
  const [refreshing, setRefreshing] = useState(false);
  const [message, setMessage] = useState<string>("");

  const handleRefresh = async () => {
    setRefreshing(true);
    setMessage("");

    try {
      const newToken = await authClient.refreshToken();

      if (newToken) {
        setMessage("Token refreshed successfully!");
      } else {
        setMessage("Failed to refresh token. Please sign in again.");
      }
    } catch (error) {
      setMessage(error instanceof Error ? error.message : "Unknown error");
    } finally {
      setRefreshing(false);
    }
  };

  return (
    <div>
      <button onClick={handleRefresh} disabled={refreshing}>
        {refreshing ? "Refreshing..." : "Refresh Token"}
      </button>
      {message && <p>{message}</p>}
    </div>
  );
}

Scheduled Refresh

Set up a scheduled refresh before the token expires:

import { authClient } from "@/auth";
import { useEffect, useRef } from "react";

function useAutoRefreshToken() {
  const timeoutRef = useRef<NodeJS.Timeout | null>(null);

  useEffect(() => {
    const scheduleRefresh = () => {
      const token = authClient.token();

      if (!token) return;

      // Calculate when to refresh (5 minutes before expiry)
      const refreshTime = (token.expires_in - 5 * 60) * 1000;

      // Clear any existing timeout
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
      }

      // Schedule the refresh
      timeoutRef.current = setTimeout(async () => {
        console.log("Auto-refreshing token...");
        const newToken = await authClient.refreshToken();

        if (newToken) {
          console.log("Token refreshed successfully");
          // Schedule the next refresh
          scheduleRefresh();
        } else {
          console.log("Failed to refresh token");
        }
      }, refreshTime);
    };

    scheduleRefresh();

    return () => {
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
      }
    };
  }, []);
}

// Usage
function App() {
  useAutoRefreshToken();

  return <div>{/* Your app content */}</div>;
}

Error Handling

The method may return null or throw errors in the following cases:

  • No refresh token: Returns null if there's no refresh token in localStorage
  • Invalid refresh token: Returns null if the refresh token is expired or invalid
  • Network errors: Throws an error for network issues
  • Server errors: Throws an error if the auth server returns an error

Always check for null and handle errors appropriately:

try {
  const newToken = await authClient.refreshToken();

  if (!newToken) {
    // Refresh token expired or invalid
    // Redirect to login
    window.location.href = "/login";
  }
} catch (error) {
  console.error("Failed to refresh token:", error);
  // Handle error
}

When to Refresh

Refresh the token when:

  • The access token is about to expire (recommended: 5 minutes before expiry)
  • An API request returns a 401 Unauthorized error
  • The user explicitly requests a refresh

Don't refresh the token when:

  • The user is not authenticated
  • The refresh token itself has expired (redirect to login instead)
  • There's no refresh token available

Token Expiration

The expires_in field in the token object indicates how many seconds the access token is valid for. Common values:

  • 3600 (1 hour) - Most common
  • 86400 (24 hours) - Long-lived tokens
  • 300 (5 minutes) - Short-lived tokens for testing

See Also