Documentation

signifyid/client

Official React SDK for Signify iD - Digital Identity & Access Management. Authenticate users in your React or Next.js app with Signify iD in under 5 minutes.

What is Signify iD?

Signify iD is a modern Digital Identity & Access Management platform that provides:

  • Single Sign-On (SSO) - One login for all your applications
  • Session Management - Secure, token-based authentication
  • User Management - Comprehensive user administration
  • Multi-Factor Authentication - Enhanced security options

This SDK enables seamless integration with Signify iD's redirect-based authentication flow.

Installation

npm
npm install signifyid/client
yarn
yarn add signifyid/client
pnpm
pnpm add signifyid/client

Quick Start (5 minutes)

1. Wrap your app with SignifyProvider

tsx
1// app/layout.tsx (Next.js App Router)
2import { SignifyProvider } from "signifyid/client";
3
4export default function RootLayout({ children }) {
5 return (
6 <html>
7 <body>
8 <SignifyProvider
9 config={{
10 apiUrl: process.env.NEXT_PUBLIC_SIGNIFY_API_URL!,
11 loginUrl: process.env.NEXT_PUBLIC_SIGNIFY_LOGIN_URL!,
12 }}
13 >
14 {children}
15 </SignifyProvider>
16 </body>
17 </html>
18 );
19}

2. Protect routes that require authentication

tsx
1// app/dashboard/page.tsx
2import { ProtectedRoute } from "signifyid/client";
3import Dashboard from "./Dashboard";
4
5export default function DashboardPage() {
6 return (
7 <ProtectedRoute>
8 <Dashboard />
9 </ProtectedRoute>
10 );
11}

3. Use the auth hook in your components

tsx
1// components/Navbar.tsx
2"use client";
3
4import { useSignifyAuth } from "signifyid/client";
5
6export function Navbar() {
7 const { isAuthenticated, isLoading, user, login, logout } = useSignifyAuth();
8
9 if (isLoading) {
10 return <nav>Loading...</nav>;
11 }
12
13 return (
14 <nav>
15 {isAuthenticated ? (
16 <>
17 <span>Welcome, {user?.name}!</span>
18 <button onClick={logout}>Logout</button>
19 </>
20 ) : (
21 <button onClick={login}>Login with Signify iD</button>
22 )}
23 </nav>
24 );
25}

4. Set up environment variables

.env.local
# .env.local
NEXT_PUBLIC_SIGNIFY_API_URL=https://api.signifyid.com
NEXT_PUBLIC_SIGNIFY_LOGIN_URL=https://signifyid.com/client/login

That's it! πŸŽ‰

Your app now supports Signify iD authentication.

API Reference

SignifyProvider

The root provider that enables Signify iD authentication throughout your app.

tsx
<SignifyProvider
  config={{
    apiUrl: string;           // Required: Backend API URL
    loginUrl: string;         // Required: Signify iD login page URL
    cookieName?: string;      // Optional: Cookie name (default: "clientSession")
    cookieMaxAge?: number;    // Optional: Cookie max age in seconds (default: 86400)
    tokenParam?: string;      // Optional: URL token parameter (default: "token")
    debug?: boolean;          // Optional: Enable debug logging (default: false)
  }}
  onAuthStateChange?: (state) => void  // Optional: Callback on auth state changes
>
  {children}
</SignifyProvider>

Config Options

OptionTypeRequiredDescription
apiUrlstringYesBackend API URL for session validation
loginUrlstringYesSignify iD login page URL
cookieNamestringNoCookie name (default: "clientSession")
cookieMaxAgenumberNoCookie max age in seconds (default: 86400)
tokenParamstringNoURL token parameter name (default: "token")
debugbooleanNoEnable debug logging (default: false)

useSignifyAuth

Hook to access authentication state and methods.

tsx
const {
  isAuthenticated,   // boolean: Whether user is authenticated
  isLoading,         // boolean: Whether auth is being validated
  session,           // SignifySession | null: Full session data
  user,              // SignifyUser | null: User data (shortcut for session.user)
  login,             // () => void: Redirect to Signify iD login
  logout,            // () => Promise<void>: Log out and clear session
  validateSession,   // () => Promise<void>: Manually re-validate session
} = useSignifyAuth();

Return Values

PropertyTypeDescription
isAuthenticatedbooleanWhether user is authenticated
isLoadingbooleanWhether auth is being validated
sessionSignifySession | nullFull session data
userSignifyUser | nullUser data (shortcut for session.user)
login() => voidRedirect to Signify iD login
logout() => Promise<void>Log out and clear session
validateSession() => Promise<void>Manually re-validate session

ProtectedRoute

Component that protects children by requiring authentication.

tsx
<ProtectedRoute
  loadingComponent?: React.ReactNode   // Optional: Custom loading UI
  redirectUrl?: string                  // Optional: Custom redirect URL
  onRedirect?: () => void              // Optional: Callback before redirect
>
  {children}
</ProtectedRoute>

Props

PropTypeDescription
loadingComponentReact.ReactNodeCustom loading UI to show during auth check
redirectUrlstringCustom URL to redirect unauthenticated users
onRedirect() => voidCallback before redirect happens

useSignifyConfig

Hook to access the resolved configuration.

tsx
const config = useSignifyConfig();
// Returns: { apiUrl, loginUrl, cookieName, cookieMaxAge, tokenParam, debug }

Authentication Flow

Authentication Flow
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    Your App     β”‚    β”‚   Signify iD    β”‚    β”‚  Signify API    β”‚
β”‚                 β”‚    β”‚   Login Page    β”‚    β”‚                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                      β”‚                      β”‚
         β”‚ 1. User visits       β”‚                      β”‚
         β”‚    protected route   β”‚                      β”‚
         β”‚                      β”‚                      β”‚
         β”‚ 2. Redirect ───────► β”‚                      β”‚
         β”‚    ?redirect=...     β”‚                      β”‚
         β”‚                      β”‚                      β”‚
         β”‚                      β”‚ 3. User logs in      β”‚
         β”‚                      β”‚                      β”‚
         β”‚ 4. Redirect back ◄── β”‚                      β”‚
         β”‚    ?token=...        β”‚                      β”‚
         β”‚                      β”‚                      β”‚
         β”‚ 5. SDK extracts token, stores in cookie     β”‚
         β”‚                      β”‚                      β”‚
         β”‚ 6. Validate session ─────────────────────► β”‚
         β”‚                      β”‚                      β”‚
         β”‚ 7. Session data ◄─────────────────────────  β”‚
         β”‚                      β”‚                      β”‚
         β”‚ 8. User authenticatedβ”‚                      β”‚
         β”‚    βœ“                 β”‚                      β”‚

Next.js Examples

App Router (Next.js 13+)

tsx
1// app/layout.tsx
2import { SignifyProvider } from "signifyid/client";
3
4export default function RootLayout({
5 children,
6}: {
7 children: React.ReactNode;
8}) {
9 return (
10 <html lang="en">
11 <body>
12 <SignifyProvider
13 config={{
14 apiUrl: process.env.NEXT_PUBLIC_SIGNIFY_API_URL!,
15 loginUrl: process.env.NEXT_PUBLIC_SIGNIFY_LOGIN_URL!,
16 debug: process.env.NODE_ENV === "development",
17 }}
18 >
19 {children}
20 </SignifyProvider>
21 </body>
22 </html>
23 );
24}
tsx
1// app/dashboard/layout.tsx
2import { ProtectedRoute } from "signifyid/client";
3
4export default function DashboardLayout({
5 children,
6}: {
7 children: React.ReactNode;
8}) {
9 return (
10 <ProtectedRoute
11 loadingComponent={
12 <div className="flex items-center justify-center min-h-screen">
13 <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500" />
14 </div>
15 }
16 >
17 {children}
18 </ProtectedRoute>
19 );
20}

Pages Router

tsx
1// pages/_app.tsx
2import type { AppProps } from "next/app";
3import { SignifyProvider } from "signifyid/client";
4
5export default function App({ Component, pageProps }: AppProps) {
6 return (
7 <SignifyProvider
8 config={{
9 apiUrl: process.env.NEXT_PUBLIC_SIGNIFY_API_URL!,
10 loginUrl: process.env.NEXT_PUBLIC_SIGNIFY_LOGIN_URL!,
11 }}
12 >
13 <Component {...pageProps} />
14 </SignifyProvider>
15 );
16}
tsx
1// pages/dashboard.tsx
2import { ProtectedRoute, useSignifyAuth } from "signifyid/client";
3
4function DashboardContent() {
5 const { user, logout } = useSignifyAuth();
6
7 return (
8 <div>
9 <h1>Welcome, {user?.name}!</h1>
10 <p>Email: {user?.email}</p>
11 <button onClick={logout}>Logout</button>
12 </div>
13 );
14}
15
16export default function DashboardPage() {
17 return (
18 <ProtectedRoute>
19 <DashboardContent />
20 </ProtectedRoute>
21 );
22}

TypeScript Support

This package is written in TypeScript and includes full type definitions.

tsx
import type {
  SignifyConfig,
  SignifySession,
  SignifyUser,
  SignifyAuthState,
  SignifyProviderProps,
  ProtectedRouteProps,
} from "signifyid/client";

Custom User Type

If your Signify iD returns additional user properties:

tsx
interface MyUser extends SignifyUser {
  organizationId: string;
  role: "admin" | "user";
}

const { user } = useSignifyAuth();
const myUser = user as MyUser | null;

Advanced Usage

Listen to Auth State Changes

tsx
1<SignifyProvider
2 config={config}
3 onAuthStateChange={(state) => {
4 if (state.isAuthenticated) {
5 analytics.identify(state.user?.id);
6 }
7 }}
8>
9 {children}
10</SignifyProvider>

Custom Redirect URL

tsx
<ProtectedRoute redirectUrl="/custom-login">
  <Dashboard />
</ProtectedRoute>

Manual Session Validation

tsx
const { validateSession } = useSignifyAuth();

// Re-validate session on demand
await validateSession();

Utility Functions

For advanced use cases, utility functions are also exported:

tsx
import {
  setCookie,
  getCookie,
  deleteCookie,
  getTokenFromUrl,
  cleanUrlParams,
  isBrowser,
} from "signifyid/client";

Security Considerations

  • SSR Safe: All browser APIs are wrapped with isBrowser() checks
  • Credentials: Uses credentials: 'include' for cross-domain cookie support
  • Token Cleanup: Automatically removes token from URL after extraction
  • Secure Cookies: Uses SameSite=Lax for CSRF protection
  • No Token Exposure: Tokens are stored in cookies, not in JavaScript state

Troubleshooting

"useSignifyAuth must be used within a SignifyProvider"

Make sure your component is a child of <SignifyProvider>:

tsx
// ❌ Wrong
<SignifyProvider>...</SignifyProvider>
<MyComponent /> // Outside provider!

// βœ… Correct
<SignifyProvider>
  <MyComponent /> // Inside provider
</SignifyProvider>

Session not persisting after redirect

  1. Ensure your apiUrl and loginUrl are correct
  2. Check if CORS is configured on your backend
  3. Verify cookies are being set (check browser DevTools β†’ Application β†’ Cookies)

Infinite redirect loop

This usually happens when session validation always returns valid: false. Check:

  1. Your backend is running and accessible
  2. The session validation endpoint is correct: POST /api/client-auth/session/validate
  3. Credentials are being sent with the request

Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

License

MIT Β© Signify iD