@drmhse/authos-react
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]
CookieStorageandBrowserStoragestore 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
cryptomodule
This duplication is intentional due to runtime differences. Both implementations verify signatures using your JWKS endpoint.
License
MIT © DRM HSE