All checks were successful
armco-org/iam-client-sdk/pipeline/head This commit looks good
- init() restores session from storage on app startup - Valid access token: re-setup autoRefresh timer - Expired access token + refresh token: silent refresh - No tokens: return false - Idempotent (safe to call multiple times) - hasRefreshToken() helper to check if silent refresh is possible - Updated isAuthenticated() JSDoc to clarify synchronous nature Fixes: sessions expiring on page reload because setupAutoRefresh() was only called in handleCallback(), timer lost on page close.
@armco/iam-client
Browser/SPA client for IAM - OIDC/OAuth2 authentication with PKCE.
Installation
npm install @armco/iam-client
Quick Start
Vanilla JavaScript/TypeScript
import { createIAMClient } from '@armco/iam-client';
const iam = createIAMClient({
issuer: 'http://localhost:5000',
clientId: 'my-app',
redirectUri: 'http://localhost:3000/callback',
scopes: ['openid', 'profile', 'email', 'offline_access'],
});
// Login
document.getElementById('login-btn').onclick = () => iam.login();
// Signup
document.getElementById('signup-btn').onclick = () => iam.signup();
// Handle callback (on /callback page)
const result = await iam.handleCallback();
if (result.success) {
console.log('Logged in:', result.user);
} else {
console.error('Login failed:', result.error);
}
// Get current user
const user = iam.getUser();
// Get access token (auto-refreshes if needed)
const token = await iam.getAccessToken();
// Logout
await iam.logout();
React
import { IAMProvider, useAuth } from '@armco/iam-client/react';
// Wrap your app
function App() {
return (
<IAMProvider
issuer="http://localhost:5000"
clientId="my-app"
redirectUri="http://localhost:3000/callback"
onLoginSuccess={(result) => {
console.log('Logged in:', result.user);
// Navigate to dashboard
}}
>
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/callback" element={<Callback />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</Router>
</StuffleIAMProvider>
);
}
// Use the hook
function Home() {
const { isAuthenticated, isLoading, user, login, signup, logout } = useAuth();
if (isLoading) return <div>Loading...</div>;
if (!isAuthenticated) {
return (
<div>
<button onClick={() => login()}>Login</button>
<button onClick={() => signup()}>Sign Up</button>
</div>
);
}
return (
<div>
<p>Welcome, {user?.name || user?.email}</p>
<button onClick={() => logout()}>Logout</button>
</div>
);
}
// Callback page (auto-handled by provider)
function Callback() {
const { isLoading, error } = useAuth();
if (isLoading) return <div>Processing login...</div>;
if (error) return <div>Error: {error.message}</div>;
return <Navigate to="/dashboard" />;
}
Configuration
interface StuffleIAMConfig {
/** IAM server base URL */
issuer: string;
/** OAuth2 client ID */
clientId: string;
/** Redirect URI after login */
redirectUri: string;
/** Requested scopes (default: openid profile email) */
scopes?: string[];
/** Post-logout redirect URI */
postLogoutRedirectUri?: string;
/** Enable PKCE (default: true) */
usePkce?: boolean;
/** Storage type (default: sessionStorage) */
storage?: 'localStorage' | 'sessionStorage' | 'memory';
/** Auto-refresh tokens (default: true) */
autoRefresh?: boolean;
/** Seconds before expiry to refresh (default: 60) */
refreshThreshold?: number;
}
React Hooks
| Hook | Description |
|---|---|
useAuth() |
Full auth context (user, login, logout, etc.) |
useUser() |
Current user object |
useIsAuthenticated() |
Boolean auth status |
useAccessToken() |
Function to get access token |
useHasRole(roles) |
Check if user has role(s) |
Protected Routes (HOC)
import { withAuth } from '@armco/iam-client/react';
const ProtectedPage = withAuth(MyComponent, {
LoadingComponent: () => <div>Loading...</div>,
UnauthorizedComponent: () => <div>Please login</div>,
roles: ['admin'], // Optional: require specific roles
});
API Reference
StuffleIAMClient Methods
| Method | Description |
|---|---|
login(options?) |
Start login flow |
signup(options?) |
Start signup flow |
logout(options?) |
End session |
handleCallback(url?) |
Process OAuth callback |
getUser() |
Get current user from ID token |
getAccessToken() |
Get access token (refreshes if needed) |
isAuthenticated() |
Check if user is logged in |
refreshToken() |
Manually refresh tokens |
subscribe(listener) |
Subscribe to auth state changes |
Development
cd packages/sdk-js
npm install
npm run build
npm run dev # Watch mode
Description
Languages
TypeScript
99.6%
Shell
0.4%