@flowsta/auth
OAuth 2.0 authentication SDK for web applications.
@flowsta/auth handles the complete OAuth 2.0 + PKCE flow for browser-based apps. Zero dependencies, TypeScript-first, with React bindings included.
Installation
npm install @flowsta/authQuick Start
import { FlowstaAuth } from '@flowsta/auth';
const auth = new FlowstaAuth({
clientId: 'your_client_id',
redirectUri: 'https://yourapp.com/auth/callback'
});
// Redirect to Flowsta login
auth.login();
// On your callback page
const user = await auth.handleCallback();
console.log('Welcome,', user.displayName);Configuration
interface FlowstaAuthConfig {
clientId: string; // Required - from dev.flowsta.com
redirectUri: string; // Required - OAuth callback URL
scopes?: string[]; // Optional - default: ['openid', 'email', 'display_name']
loginUrl?: string; // Optional - default: 'https://login.flowsta.com'
apiUrl?: string; // Optional - default: 'https://auth-api.flowsta.com'
}No Client Secret Required
Flowsta uses PKCE (Proof Key for Code Exchange) which provides security without client secrets. Works safely in browsers and mobile apps.
Methods
login()
Redirect user to Flowsta's login page.
auth.login();handleCallback()
Handle the OAuth callback and retrieve user data. Call this on your redirect URI page.
const user = await auth.handleCallback();isAuthenticated()
Check if user is logged in.
if (auth.isAuthenticated()) {
const user = auth.getUser();
}getUser()
Get the current user profile.
const user = auth.getUser();
// { id, email?, username?, displayName?, profilePicture?, agentPubKey?, did?, linkedAgents?, signingMode? }getAccessToken()
Get the current access token.
const token = auth.getAccessToken();getState()
Get the full authentication state.
const state = auth.getState();
// { isAuthenticated, user, accessToken, isLoading, error }logout()
Clear the local session.
auth.logout();detectVault()
Check if Flowsta Vault is running locally.
const vault = await auth.detectVault();
// { running: boolean, agentPubKey?: string, did?: string }
if (vault.running) {
console.log('Vault agent:', vault.agentPubKey);
}getLinkedAgents(agentPubKey?)
Get agents linked to a specific agent, or the current user's agent if no key is provided. Returns an array of agent public key strings.
// Get agents linked to current user
const agents = await auth.getLinkedAgents();
// ['uhCAk...', 'uhCAk...']
// Get agents linked to a specific agent
const agents = await auth.getLinkedAgents('uhCAk7Jp...');areAgentsLinked(agentA, agentB)
Check if two agents are linked via Flowsta identity.
const linked = await auth.areAgentsLinked(agentKeyA, agentKeyB);Type Definitions
interface FlowstaUser {
id: string;
email?: string;
username?: string;
displayName?: string;
profilePicture?: string;
agentPubKey?: string; // Holochain agent public key
did?: string; // W3C Decentralized Identifier
linkedAgents?: LinkedAgent[]; // Linked agents (DHT-verified)
signingMode?: 'remote' | 'ipc'; // 'remote' = API, 'ipc' = Vault
}
interface LinkedAgent {
agentPubKey: string; // The linked agent's public key
linkedAt?: string; // When the link was created
isRevoked: boolean; // Whether the link has been revoked
}
interface VaultDetectionResult {
running: boolean; // Whether Vault is running
agentPubKey?: string; // Vault agent's public key (if unlocked)
did?: string; // Vault agent's DID (if unlocked)
}
interface AuthState {
isAuthenticated: boolean;
user: FlowstaUser | null;
accessToken: string | null;
isLoading: boolean;
error: string | null;
}React Integration
import { FlowstaAuthProvider, useFlowstaAuth } from '@flowsta/auth/react';
function App() {
return (
<FlowstaAuthProvider
clientId="your_client_id"
redirectUri="https://yourapp.com/auth/callback"
>
<MyApp />
</FlowstaAuthProvider>
);
}
function LoginButton() {
const { isAuthenticated, user, login, logout } = useFlowstaAuth();
if (isAuthenticated) {
return (
<div>
<span>Hello, {user.displayName}!</span>
<button onClick={logout}>Logout</button>
</div>
);
}
return <button onClick={login}>Sign in with Flowsta</button>;
}Provider Required
useFlowstaAuth() must be used within a FlowstaAuthProvider. If used outside, it will throw: "useFlowstaAuth must be used within a FlowstaAuthProvider".
useRequireAuth()
Protect routes by redirecting unauthenticated users. Returns an isReady flag that is true once the user is confirmed authenticated.
import { useRequireAuth } from '@flowsta/auth/react';
function ProtectedPage() {
const { isReady, user } = useRequireAuth();
// Optionally pass a custom redirect: useRequireAuth({ redirectTo: '/login' })
if (!isReady) {
return <div>Loading...</div>;
}
return <div>Welcome, {user?.displayName}!</div>;
}Error Handling
handleCallback() throws specific errors you can catch:
try {
const user = await auth.handleCallback();
} catch (error) {
switch (true) {
case error.message.includes('No authorization code'):
// User cancelled login or error from Flowsta
break;
case error.message.includes('Invalid state'):
// CSRF attack or expired session
break;
case error.message.includes('Missing PKCE code verifier'):
// Session was cleared before callback (e.g. different browser tab)
break;
case error.message.includes('Token exchange failed'):
// Code expired (10 min limit) or server error
break;
case error.message.includes('Failed to fetch user info'):
// Token was issued but userinfo request failed
break;
default:
console.error('Authentication failed:', error.message);
}
}Security
The SDK automatically handles:
- PKCE - Generates
code_verifierandcode_challengefor each login - State parameter - Random state stored in
sessionStoragefor CSRF protection - Secure storage - Access and refresh tokens in
localStorage, PKCE/state insessionStorage(cleared after use) - Session restoration - Authenticated state persists across page reloads via
localStorage - Refresh tokens - Stored in
localStorageasflowsta_refresh_tokenfor long-lived sessions
Migrating from SDK 1.x
SDK 2.0 removes direct email/password authentication. All users now authenticate through Flowsta's hosted login page.
Before (SDK 1.x):
// No longer supported
await auth.login(email, password);After (SDK 2.0+):
// OAuth redirect
auth.login(); // Redirects to login.flowsta.com
const user = await auth.handleCallback();Next Steps
- Auth Overview - OAuth flow documentation
- Login Button Widget - Pre-built buttons
- OAuth API Reference - REST endpoints
- Security Guide - Best practices