Skip to main content

React SDK

React components and hooks for adding authentication to your frontend application.

Features​

  • AuthProvider - Context provider for authentication state
  • useAuth / useUser - Hooks for accessing user data
  • LoginButton / LogoutButton - Pre-built authentication buttons
  • RequireAuth - Component for protecting routes

Installation​

npm install @groo.dev/auth-react

Quick Start​

import { AuthProvider, useAuth, LoginButton, LogoutButton } from '@groo.dev/auth-react'

// 1. Wrap your app
function App() {
return (
<AuthProvider
baseUrl="http://localhost:8787"
clientId="your-client-id"
redirectUri="http://localhost:3000"
>
<YourApp />
</AuthProvider>
)
}

// 2. Use in components
function Header() {
const { user, isLoading } = useAuth()

if (isLoading) return <div>Loading...</div>

return user ? (
<>
<span>Welcome, {user.name}</span>
<LogoutButton>Sign Out</LogoutButton>
</>
) : (
<LoginButton>Sign In</LoginButton>
)
}

AuthProvider Setup​

Wrap your app with AuthProvider:

import { AuthProvider } from '@groo.dev/auth-react'

function App() {
return (
<AuthProvider
baseUrl="http://localhost:8787"
clientId="your-client-id"
redirectUri="http://localhost:3000"
>
<YourApp />
</AuthProvider>
)
}

Configuration Options​

PropTypeRequiredDescription
baseUrlstringYesYour API's base URL (not accounts service)
clientIdstringYesYour application's client ID
redirectUristringYesWhere to redirect after auth
Important

The baseUrl should point to your own API, not the accounts service. The AuthProvider calls GET /v1/__auth/me on your API.

Next.js Setup​

For Next.js, create a client component for the provider:

// app/providers.tsx
'use client'

import { AuthProvider } from '@groo.dev/auth-react'

export function Providers({ children }: { children: React.ReactNode }) {
return (
<AuthProvider
baseUrl={process.env.NEXT_PUBLIC_BASE_URL!}
clientId={process.env.NEXT_PUBLIC_CLIENT_ID!}
redirectUri={process.env.NEXT_PUBLIC_REDIRECT_URI!}
>
{children}
</AuthProvider>
)
}

Then wrap your app in layout.tsx:

// app/layout.tsx
import { Providers } from './providers'

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}

Hooks​

useAuth​

The primary hook for accessing authentication state and URLs:

import { useAuth } from '@groo.dev/auth-react'

function Profile() {
const { user, isLoading, error, loginUrl, logoutUrl, refetch } = useAuth()

if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
if (!user) return <a href={loginUrl}>Sign In</a>

return (
<div>
<h1>Welcome, {user.name || user.email}!</h1>
<a href={logoutUrl}>Sign Out</a>
</div>
)
}

Return Values​

PropertyTypeDescription
userUser | nullCurrent authenticated user
isLoadingbooleanWhether auth state is loading
errorError | nullError if auth fetch failed
loginUrlstringGenerated login URL
logoutUrlstringGenerated logout URL
refetch() => Promise<void>Manually refetch user data

useUser​

Alternative hook that returns only user data (without URLs):

import { useUser } from '@groo.dev/auth-react'

function Avatar() {
const { user, isLoading, error } = useUser()

if (isLoading || !user) return null

return (
<div>
<img src={user.avatar} alt={user.name} />
<span>{user.name}</span>
</div>
)
}

Manual Refetch​

Refetch user data after an action:

function UpdateProfile() {
const { refetch } = useAuth()

async function handleUpdate() {
await updateProfileAPI()
await refetch() // Refresh user data
}

return <button onClick={handleUpdate}>Update</button>
}

Components​

LoginButton​

Links to the login URL:

import { LoginButton } from '@groo.dev/auth-react'

function Header() {
return (
<nav>
<LoginButton>Sign In</LoginButton>
</nav>
)
}

With custom styling:

<LoginButton className="btn btn-primary">
Get Started
</LoginButton>

LogoutButton​

Links to the logout URL:

import { LogoutButton } from '@groo.dev/auth-react'

function Header() {
return (
<nav>
<LogoutButton>Sign Out</LogoutButton>
</nav>
)
}

RequireAuth​

Protects content by only rendering children when authenticated:

import { RequireAuth } from '@groo.dev/auth-react'

function Dashboard() {
return (
<RequireAuth fallback={<div>Loading...</div>}>
<DashboardContent />
</RequireAuth>
)
}

With redirect to login:

<RequireAuth redirectTo="/login">
<ProtectedContent />
</RequireAuth>

Props​

PropTypeDescription
childrenReactNodeContent to show when authenticated
fallbackReactNodeContent to show while loading or unauthenticated
redirectTostringURL to redirect to if not authenticated

Complete Example​

import { useAuth, LoginButton, LogoutButton, RequireAuth } from '@groo.dev/auth-react'

function App() {
const { user, isLoading, error } = useAuth()

if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>

return (
<div>
<header>
<h1>My App</h1>
{user ? (
<div>
<span>Hello, {user.name || user.email}</span>
<LogoutButton>Sign Out</LogoutButton>
</div>
) : (
<LoginButton>Sign In</LoginButton>
)}
</header>

<main>
<RequireAuth fallback={<p>Please sign in to continue</p>}>
<Dashboard user={user} />
</RequireAuth>
</main>
</div>
)
}

Requirements​

  • A backend API with @groo.dev/auth-server that handles session validation
  • A registered application at accounts.groo.dev