useDeva

React hook for accessing authentication state and user information.


Import

import { useDeva } from "@bitplanet/deva-sdk";

Relationship with DevaProvider

useDeva and DevaProvider work together as a React Context pattern:

DevaProvider (Component):

  • Wraps your application at the root level

  • Manages OAuth authentication flow

  • Handles token refresh automatically

  • Stores authentication state in React Context

  • Provides configuration (clientId, redirectUri, env)

useDeva (Hook):

  • Consumes the Context created by DevaProvider

  • Provides a simplified API for child components

  • Returns only essential properties for application use

  • Cannot be used outside of DevaProvider

Relationship:

<DevaProvider clientId="..." redirectUri="..." env="...">
  {/* DevaProvider creates and manages auth state */}

  <MyComponent />
  {/* useDeva() accesses the auth state */}
</DevaProvider>

Think of it as:

  • DevaProvider = Authentication engine (does the work)

  • useDeva = Dashboard (shows you the results)

Learn more about DevaProvider →


What It Does

Provides access to:

  • User authentication status

  • User profile information

  • Login/logout functions

  • Access token for API calls

Must be used inside a DevaProvider component.


Basic Usage

import { useDeva } from "@bitplanet/deva-sdk";

function MyComponent() {
  const { isAuthenticated, user, login, logout } = useDeva();

  if (!isAuthenticated) {
    return <button onClick={login}>Login with Deva</button>;
  }

  return (
    <div>
      <p>Welcome, {user?.persona?.display_name}!</p>
      <button onClick={logout}>Logout</button>
    </div>
  );
}

Return Values

interface UseDevaReturn {
  isAuthenticated: boolean;       // Is user logged in?
  isReady: boolean;              // Is SDK initialized?
  user: UserInfo | null;         // User profile data
  accessToken: string | null;    // JWT token for API calls
  login: () => Promise<void>;    // Start login flow
  logout: () => Promise<void>;   // End session
}

isAuthenticated

Type: boolean

Indicates whether the user is currently authenticated.

Values:

  • true - User has valid access token

  • false - User not logged in or token expired

Usage: Check if user is logged in

const { isAuthenticated } = useDeva();

if (isAuthenticated) {
  return <Dashboard />;
}
return <LoginPage />;

isReady

Type: boolean Indicates whether the SDK has finished initializing.

Values:

  • true - SDK initialization complete, safe to check authentication

  • false - SDK still loading OpenID configuration

Usage: Check if SDK finished initializing

Important: Always check isReady before using isAuthenticated

const { isReady, isAuthenticated } = useDeva();

if (!isReady) {
  return <div>Loading...</div>;
}

if (!isAuthenticated) {
  return <LoginPage />;
}

return <App />;

user

Type: UserInfo | null

Complete user information including profile and persona data.

Contains:

interface UserInfo {
  sub: string;                 // User ID
  preferred_username: string;  // Username
  email?: string;             // Email
  email_verified?: boolean;   // Email verified?
  picture?: string;           // Profile picture URL
  persona: {
    id: string;
    username: string;
    display_name: string;
    avatar: string;
    bio?: string;
  };
}

Usage:

const { user } = useDeva();

return (
  <div>
    <img src={user?.persona.avatar} />
    <h2>{user?.persona.display_name}</h2>
    <p>@{user?.preferred_username}</p>
  </div>
);

accessToken

Type: string | null

The current OAuth access token.

Values:

  • JWT string when authenticated

  • null when not authenticated

Usage: Include in API requests

const { accessToken } = useDeva();

// Use for custom API calls
if (accessToken) {
  fetch("https://api.deva.me/custom", {
    headers: {
      Authorization: `Bearer ${accessToken}`
    }
  });
}

Note: SDK components automatically include the token. You only need this for custom API calls.


login

Type: () => Promise<void>

Initiates the OAuth 2.0 authentication flow.

Usage: Initiate OAuth login flow

const { login } = useDeva();

<button onClick={login}>Sign in with Deva</button>

What happens:

  1. Redirects user to Deva login page

  2. User authenticates

  3. Redirects back to your app

  4. SDK exchanges code for tokens

  5. isAuthenticated becomes true


logout

Type: () => Promise<void>

Revokes tokens and clears authentication state.

Usage: End user session

const { logout } = useDeva();

<button onClick={logout}>Logout</button>

What happens:

  1. Revokes tokens on server

  2. Clears local session data

  3. isAuthenticated becomes false

  4. user becomes null


Common Patterns

Protected Route

function ProtectedRoute({ children }) {
  const { isReady, isAuthenticated, login } = useDeva();

  if (!isReady) {
    return <div>Loading...</div>;
  }

  if (!isAuthenticated) {
    return <button onClick={login}>Login Required</button>;
  }

  return <>{children}</>;
}

User Profile Display

function UserProfile() {
  const { user, isAuthenticated } = useDeva();

  if (!isAuthenticated || !user) {
    return null;
  }

  return (
    <div>
      <img src={user.persona.avatar} alt={user.preferred_username} />
      <h3>{user.persona.display_name}</h3>
      <p>@{user.preferred_username}</p>
      {user.email_verified && <span>✓ Verified</span>}
    </div>
  );
}

Login/Logout Toggle

function AuthButton() {
  const { isAuthenticated, user, login, logout } = useDeva();

  return isAuthenticated ? (
    <button onClick={logout}>
      Logout ({user?.preferred_username})
    </button>
  ) : (
    <button onClick={login}>Login</button>
  );
}

Custom API Call

function CustomData() {
  const { accessToken, isAuthenticated } = useDeva();
  const [data, setData] = useState(null);

  const fetchData = async () => {
    if (!isAuthenticated || !accessToken) return;

    const response = await fetch("/api/custom", {
      headers: {
        Authorization: `Bearer ${accessToken}`,
      },
    });

    setData(await response.json());
  };

  return <button onClick={fetchData}>Fetch Data</button>;
}

Important Notes

Must Use Inside DevaProvider

// ❌ Error: useDeva must be used within a DevaProvider
function App() {
  const { user } = useDeva(); // Will throw error
  return <div>{user?.name}</div>;
}
// ✅ Correct
import { DevaProvider } from "@bitplanet/deva-sdk";

function App() {
  return (
    <DevaProvider clientId="..." redirectUri="..." env="...">
      <MyComponent /> {/* Can use useDeva here */}
    </DevaProvider>
  );
}

Always Check isReady First

// ❌ Bad: May flash wrong state during initialization
const { isAuthenticated } = useDeva();
if (!isAuthenticated) return <Login />;
// ✅ Good: Wait for SDK to initialize
const { isReady, isAuthenticated } = useDeva();
if (!isReady) return <Loading />;
if (!isAuthenticated) return <Login />;

Handle Null User

// ✅ Use optional chaining
const displayName = user?.persona.display_name || "Guest";
const avatar = user?.picture || user?.persona.avatar || "/default.png";

TypeScript

Full type definitions:

import { useDeva } from "@bitplanet/deva-sdk";
import type { UserInfo } from "@bitplanet/deva-sdk";

interface UseDevaReturn {
  isAuthenticated: boolean;
  isReady: boolean;
  accessToken: string | null;
  user: UserInfo | null;
  login: () => Promise<void>;
  logout: () => Promise<void>;
}

const useDeva: () => UseDevaReturn;

Last updated