getToken

The getToken method exchanges an authorization code for access tokens. It's a core part of the OAuth2/OIDC flow with PKCE, typically used in redirect mode authentication.

This method is accessed via authClient.getToken() and handles the token exchange after the user is redirected back from the authorization server.


Method Signature

getToken(code: string, state: string): Promise<void>

Parameters

code

  • type: string
  • Required - The authorization code received from the OAuth2 provider

state

  • type: string
  • Required - The state parameter for CSRF protection validation

Return Value

Returns Promise<void>. The method doesn't return tokens directly but stores them in localStorage and redirects to the callback URL.


How It Works

  1. Validates the state parameter against the value stored in sessionStorage (CSRF protection)
  2. Retrieves the PKCE code verifier from sessionStorage
  3. Exchanges the authorization code for tokens by making a POST request to /api/auth/oauth2/token
  4. Stores the tokens in localStorage
  5. Handles the flow mode:
    • Popup mode: Sends tokens to the parent window via postMessage and closes the popup
    • Redirect mode: Redirects to the stored callback URL

Usage

Redirect Mode Callback Page

This is the most common use case. Create a callback page that handles the authorization code:

// pages/auth/callback/page.tsx
import { useEffect } from "react";
import { authClient } from "@/auth";
import { useNavigate } from "react-router-dom";

export default function AuthCallback() {
  const navigate = useNavigate();

  useEffect(() => {
    const handleCallback = async () => {
      try {
        const params = new URLSearchParams(window.location.search);
        const code = params.get("code");
        const state = params.get("state");

        if (code && state) {
          // This will exchange the code for tokens and redirect
          await authClient.getToken(code, state);
        } else {
          // No code or state, redirect to home
          navigate("/");
        }
      } catch (error) {
        console.error("Failed to complete sign in:", error);
        navigate("/login");
      }
    };

    handleCallback();
  }, [navigate]);

  return (
    <div className="flex items-center justify-center min-h-screen">
      <div className="text-center">
        <h2>Completing sign in...</h2>
        <p>Please wait while we complete your authentication.</p>
      </div>
    </div>
  );
}

With Error Handling

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

export default function AuthCallback() {
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const handleCallback = async () => {
      try {
        const params = new URLSearchParams(window.location.search);
        const code = params.get("code");
        const state = params.get("state");
        const error = params.get("error");
        const errorDescription = params.get("error_description");

        if (error) {
          setError(errorDescription || error);
          return;
        }

        if (!code || !state) {
          setError("Missing authorization code or state parameter");
          return;
        }

        await authClient.getToken(code, state);
      } catch (err) {
        setError(err instanceof Error ? err.message : "Unknown error occurred");
      }
    };

    handleCallback();
  }, []);

  if (error) {
    return (
      <div>
        <h2>Authentication Failed</h2>
        <p>{error}</p>
        <a href="/login">Try Again</a>
      </div>
    );
  }

  return <div>Completing sign in...</div>;
}

For popup mode, you typically don't need to call getToken directly. The auth client handles it automatically:

// The popup window automatically calls getToken and closes itself
// You only need to handle it in your main window:

import { authClient } from "@/auth";
import { AuthMode } from "@vuer-ai/vuer-auth-client";

function LoginButton() {
  const handleLogin = async () => {
    // Popup window will handle getToken automatically
    const token = await authClient.signIn({
      authMode: AuthMode.Popup,
      callbackUrl: "/dashboard",
    });

    if (token) {
      console.log("Successfully authenticated!");
    }
  };

  return <button onClick={handleLogin}>Sign In</button>;
}

Security Features

The getToken method implements several security measures:

  1. PKCE (Proof Key for Code Exchange)

    • Uses code_verifier stored in sessionStorage
    • Prevents authorization code interception attacks
  2. State Parameter Validation

    • Validates the state parameter against sessionStorage
    • Prevents CSRF (Cross-Site Request Forgery) attacks
  3. Automatic Cleanup

    • Clears PKCE parameters from sessionStorage after use
    • Prevents replay attacks

Error Handling

The method may throw errors in the following cases:

  • Invalid state parameter: State doesn't match the stored value
  • Missing code verifier: PKCE verifier not found in sessionStorage
  • Network errors: Failed to communicate with the auth server
  • Invalid authorization code: Code is expired or already used

Storage Keys Used

The method interacts with these storage keys:

  • pkce_state (sessionStorage): Stores the state parameter for validation
  • pkce_verifier (sessionStorage): Stores the PKCE code verifier
  • vuer_callback_url (sessionStorage): Stores the callback URL for redirect
  • vuer_token (localStorage): Stores the obtained tokens

See Also