@drmhse/authos-react

React adapter for AuthOS.

Updated Jan 3, 2026 Edit this page

@drmhse/authos-react

npm version License: MIT

React adapter for AuthOS - the multi-tenant authentication platform. Provides React hooks, components, and Next.js integration.

Quick Start (5 minutes)

npm install @drmhse/authos-react

Wrap your app with AuthOSProvider and you’re ready to go:

import { AuthOSProvider, SignIn, SignedIn, SignedOut, UserButton } from '@drmhse/authos-react';

function App() {
  return (
    <AuthOSProvider config={{ baseURL: 'https://sso.example.com' }}>
      <SignedOut>
        <SignIn onSuccess={(user) => console.log('Welcome', user.email)} />
      </SignedOut>
      <SignedIn>
        <UserButton />
        <p>You're signed in!</p>
      </SignedIn>
    </AuthOSProvider>
  );
}

That’s it. You now have:

  • Email/password authentication with MFA support
  • Automatic session management
  • User dropdown with logout
  • Conditional rendering based on auth state

Usage Modes

AuthOS supports two usage modes:

Platform-Level Access

For platform owners and administrators, use without org/service:

<AuthOSProvider config={{ baseURL: 'https://sso.example.com' }}>
  <SignIn />
</AuthOSProvider>

Multi-Tenant Access (Organizations)

For tenant applications with OAuth support, add org and service:

<AuthOSProvider config={{
  baseURL: 'https://sso.example.com',
  org: 'acme-corp',    // Organization slug
  service: 'main-app', // Service slug  
}}>
  <SignIn providers={['github', 'google']} />
</AuthOSProvider>

To use OAuth providers (GitHub, Google, Microsoft), you need to configure your organization and service in the provider:

<AuthOSProvider config={{
  baseURL: 'https://sso.example.com',
  org: 'my-org',           // Your organization slug
  service: 'my-app',       // Your service slug
  redirectUri: 'https://app.example.com/callback', // Optional
}}>
  <SignIn providers={['github', 'google', 'microsoft']} />
</AuthOSProvider>

Using an Existing Client

For advanced use cases, you can pass a pre-configured SsoClient:

import { SsoClient } from '@drmhse/sso-sdk';
import { AuthOSProvider } from '@drmhse/authos-react';

// Create client with custom configuration
const client = new SsoClient({
  baseURL: 'https://sso.example.com',
  storage: customStorage,
});

function App() {
  return (
    <AuthOSProvider client={client}>
      <SignIn />
    </AuthOSProvider>
  );
}

Or use individual OAuth buttons:

import { OAuthButton } from '@drmhse/authos-react';

<OAuthButton provider="github">Sign in with GitHub</OAuthButton>
<OAuthButton provider="google" />
<OAuthButton provider="microsoft" />

Components

SignIn

Complete sign-in form with email/password authentication and optional OAuth buttons.

<SignIn
  onSuccess={(user) => console.log('Logged in:', user)}
  onError={(error) => console.error(error)}
  providers={['github', 'google']}   // Optional OAuth buttons
  showForgotPassword={true}          // Show forgot password link
  showSignUp={true}                  // Show sign up link
  showDivider={true}                 // Show "or" divider between OAuth and email form
/>

Props:

Prop Type Default Description
onSuccess (user: UserProfile) => void - Callback after successful login
onError (error: Error) => void - Callback on login error
providers ('github' | 'google' | 'microsoft')[] | false false OAuth providers to display
showForgotPassword boolean true Show forgot password link
showSignUp boolean true Show sign up link
showDivider boolean true Show divider between OAuth and email form
className string - Custom class name

SignUp

Registration form for new users.

<SignUp
  onSuccess={() => console.log('Check your email!')}
  onError={(error) => console.error(error)}
  orgSlug="my-org"  // Optional: pre-fill organization
/>

MagicLinkSignIn

Sign-in component for Magic Links (passwordless).

<MagicLinkSignIn onSuccess={() => console.log('Magic link sent!')} />

PasskeySignIn

Sign-in component for Passkeys (WebAuthn).

<PasskeySignIn onSuccess={() => console.log('Authenticated!')} />

SignedIn / SignedOut

Conditional rendering based on authentication state. Inspired by Clerk’s API.

<SignedIn>
  {/* Only shown when user is logged in */}
  <UserButton />
</SignedIn>

<SignedOut>
  {/* Only shown when user is logged out */}
  <SignIn />
</SignedOut>

UserButton

User menu button with avatar initials and dropdown with profile/signout.

<UserButton
  showEmail={true}
  onLogout={() => router.push('/')}
/>

OrganizationSwitcher

Dropdown to switch between organizations (for multi-tenant users).

When switching organizations, the SDK automatically issues new JWT tokens with the new organization context, enabling seamless multi-tenant switching without re-authentication.

<OrganizationSwitcher
  onSwitch={(org) => console.log('Switched to:', org.name)}
/>

Protect

Conditional rendering based on user permissions or roles.

<Protect permission="admin:access" fallback={<p>Access denied</p>}>
  <AdminDashboard />
</Protect>

<Protect role="owner">
  <DangerZone />
</Protect>

OAuthButton

Individual OAuth provider button. Requires org and service in provider config.

<OAuthButton provider="github" />
<OAuthButton provider="google">Continue with Google</OAuthButton>

Hooks

useAuthOS

Access the AuthOS client and auth state.

const { client, config, isAuthenticated, isLoading } = useAuthOS();

// Use the client directly
await client.auth.logout();

useUser

Get the current user’s profile.

const { user, isLoading } = useUser();

if (isLoading) return <Spinner />;
if (!user) return <SignIn />;

return <p>Welcome, {user.email}</p>;

useOrganization

Get and switch between organizations.

const { 
  currentOrganization, 
  organizations, 
  switchOrganization, 
  isSwitching 
} = useOrganization();

// Switch to a different org
await switchOrganization('other-org-slug');

usePermission / useAnyPermission / useAllPermissions

Check user permissions.

const canAccessAdmin = usePermission('admin:access');
const canReadOrWrite = useAnyPermission(['read:data', 'write:data']);
const hasFullAccess = useAllPermissions(['read:data', 'write:data', 'delete:data']);

if (!canAccessAdmin) return <AccessDenied />;

Next.js Integration

App Router

// app/layout.tsx
import { AuthOSProvider } from '@drmhse/authos-react';
import { cookies } from 'next/headers';

export default async function RootLayout({ children }) {
  const cookieStore = cookies();
  const token = cookieStore.get('authos_token')?.value;

  return (
    <html>
      <body>
        <AuthOSProvider
          config={{ baseURL: process.env.NEXT_PUBLIC_SSO_URL! }}
          initialSessionToken={token}
        >
          {children}
        </AuthOSProvider>
      </body>
    </html>
  );
}

Middleware (Next.js)

// middleware.ts
import { authMiddleware, getJwksUrl } from '@drmhse/authos-react/nextjs';

export default authMiddleware({
  jwksUrl: getJwksUrl(process.env.NEXT_PUBLIC_SSO_URL!),
  protectedRoutes: ['/dashboard/*', '/settings/*'],
  publicRoutes: ['/', '/about', '/pricing'],
  signInUrl: '/signin',
});

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

Server Components

// app/dashboard/page.tsx
import { currentUser } from '@drmhse/authos-react/nextjs';

export default async function Dashboard() {
  const user = await currentUser();
  
  if (!user) {
    redirect('/login');
  }

  return <div>Welcome, {user.email}</div>;
}

Configuration Reference

AuthOSProvider Props

Prop Type Required Description
config.baseURL string Yes AuthOS API URL
config.org string For OAuth Organization slug for OAuth flows
config.service string For OAuth Service slug for OAuth flows
config.redirectUri string - OAuth redirect URI (defaults to origin + ‘/callback’)
config.afterSignInUrl string - Redirect URL after sign-in
config.afterSignUpUrl string - Redirect URL after sign-up
config.storage TokenStorage - Custom token storage
client SsoClient - Use existing client instance
initialSessionToken string - SSR token for hydration

Styling

All components use data attributes for styling hooks. Use CSS selectors:

[data-authos-signin] { /* Container */ }
[data-authos-field="email"] { /* Email field wrapper */ }
[data-authos-field="password"] { /* Password field wrapper */ }
[data-authos-submit] { /* Submit button */ }
[data-authos-error] { /* Error message */ }
[data-authos-oauth] { /* OAuth button */ }
[data-authos-oauth][data-provider="github"] { /* GitHub button */ }
[data-authos-divider] { /* "or" divider */ }
[data-authos-magic-link] { /* Magic Link container */ }
[data-authos-passkey] { /* Passkey container */ }

Security Considerations

Token Storage

The SDK offers multiple storage options:

Storage Environment Security Notes
BrowserStorage Client-side Uses localStorage, accessible to JS
CookieStorage SSR (Next.js) Non-httpOnly cookies, accessible to JS
MemoryStorage SSR/Testing In-memory, lost on page refresh

[!WARNING] CookieStorage and BrowserStorage store tokens accessible to JavaScript. For maximum security in production, consider:

  • Using httpOnly cookies set by your backend
  • Implementing a Backend-for-Frontend (BFF) pattern
  • Ensuring proper CSP headers to mitigate XSS

JWT Verification

The Next.js middleware and Node adapter provide independent JWT verification:

  • Next.js middleware: Uses Web Crypto API (crypto.subtle) for Edge Runtime
  • Node adapter: Uses Node.js crypto module

This duplication is intentional due to runtime differences. Both implementations verify signatures using your JWKS endpoint.

License

MIT © DRM HSE