SDK Overview
The Flowsta Auth SDK (@flowsta/auth) provides OAuth-only authentication for web applications. All authentication flows through Flowsta's hosted login page.
Features
- ✅ OAuth 2.0 + PKCE - Secure authentication without client secrets
- ✅ TypeScript-first - Full type safety and IntelliSense support
- ✅ Zero dependencies - Lightweight and fast
- ✅ Zero-knowledge - User data stays private
- ✅ Universal - Works in browsers and React apps
Installation
npm install @flowsta/authBasic Usage
import { FlowstaAuth } from '@flowsta/auth';
const auth = new FlowstaAuth({
clientId: 'your_client_id',
redirectUri: 'https://yourapp.com/auth/callback'
});
// Redirect to login
auth.login();
// On callback page
const user = await auth.handleCallback();Configuration Options
FlowstaAuthConfig
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
clientId | string | ✅ Yes | - | Your application's client ID |
redirectUri | string | ✅ Yes | - | OAuth callback URL |
scopes | string[] | ❌ No | ['profile', 'email'] | OAuth scopes to request |
loginUrl | string | ❌ No | https://login.flowsta.com | Flowsta login URL |
apiUrl | string | ❌ No | https://auth-api.flowsta.com | Flowsta API URL |
interface FlowstaAuthConfig {
clientId: string;
redirectUri: string;
scopes?: string[];
loginUrl?: string;
apiUrl?: string;
}No Client Secret Required
Unlike traditional OAuth, Flowsta uses PKCE (Proof Key for Code Exchange) which provides the same security as a client secret but works safely in browsers and mobile apps.
Core Methods
login()
Redirect user to Flowsta login page.
auth.login();
// User is redirected to login.flowsta.com
// After authentication, they're redirected back to your redirectUrihandleCallback()
Handle OAuth callback and retrieve user data. Call this on your redirect URI page.
const user = await auth.handleCallback();
// user contains:
// - id: string
// - email?: string
// - username?: string
// - displayName?: string
// - profilePicture?: string
// - agentPubKey?: string
// - did?: stringisAuthenticated()
Check if user is logged in.
if (auth.isAuthenticated()) {
console.log('User is logged in');
}getUser()
Get the current user.
const user = auth.getUser();
if (user) {
console.log('Hello,', user.displayName);
console.log('Username:', user.username);
}getAccessToken()
Get the current access token for API calls.
const token = auth.getAccessToken();
// Use for API requests
fetch('/api/data', {
headers: { 'Authorization': `Bearer ${token}` }
});logout()
Log out the current user.
auth.logout();
// Clears local session storagegetState()
Get the full authentication state.
const state = auth.getState();
// {
// isAuthenticated: boolean,
// user: FlowstaUser | null,
// accessToken: string | null,
// isLoading: boolean,
// error: string | null
// }Type Definitions
interface FlowstaUser {
/** User's unique ID */
id: string;
/** Email address (if 'email' scope granted) */
email?: string;
/** Username (if set by user) */
username?: string;
/** Display name */
displayName?: string;
/** Profile picture URL */
profilePicture?: string;
/** Holochain agent public key */
agentPubKey?: string;
/** W3C Decentralized Identifier */
did?: string;
}
interface AuthState {
isAuthenticated: boolean;
user: FlowstaUser | null;
accessToken: string | null;
isLoading: boolean;
error: string | null;
}React Integration
The SDK includes React hooks for easy integration:
import { FlowstaAuthProvider, useFlowstaAuth } from '@flowsta/auth/react';
// Wrap your app
function App() {
return (
<FlowstaAuthProvider
clientId="your_client_id"
redirectUri="https://yourapp.com/auth/callback"
>
<MyApp />
</FlowstaAuthProvider>
);
}
// Use in components
function LoginButton() {
const { isAuthenticated, user, login, logout } = useFlowstaAuth();
if (isAuthenticated) {
return (
<div>
<span>Hello, {user.displayName}!</span>
{user.username && <span> (@{user.username})</span>}
<button onClick={logout}>Logout</button>
</div>
);
}
return <button onClick={login}>Sign in with Flowsta</button>;
}Error Handling
The SDK throws errors for various scenarios:
try {
const user = await auth.handleCallback();
} catch (error) {
if (error.message.includes('Invalid state')) {
// CSRF attack or expired session
console.error('Security error - please try again');
} else if (error.message.includes('No authorization code')) {
// User cancelled or error from Flowsta
console.error('Authentication was cancelled');
} else {
console.error('Authentication failed:', error.message);
}
}Security Features
PKCE (Proof Key for Code Exchange)
The SDK automatically handles PKCE:
- Generates a random
code_verifier(128 characters) - Creates a
code_challenge(SHA-256 hash) - Sends
code_challengewith authorization request - Sends
code_verifierwith token exchange
This prevents authorization code interception attacks without needing a client secret.
State Parameter
The SDK automatically:
- Generates a random
stateparameter - Stores it in
sessionStorage - Verifies it on callback
This prevents CSRF attacks.
Secure Storage
- Access tokens stored in
localStorage - PKCE verifiers stored in
sessionStorage(cleared after use) - State parameter stored in
sessionStorage(cleared after use)
Best Practices
1. Handle Errors Gracefully
try {
const user = await auth.handleCallback();
// Success - redirect to app
window.location.href = '/dashboard';
} catch (error) {
// Show user-friendly error
showError('Login failed. Please try again.');
// Redirect to login page
window.location.href = '/login';
}2. Check Authentication on Page Load
// On protected pages
if (!auth.isAuthenticated()) {
// Redirect to login
window.location.href = '/login';
}3. Handle Token Expiration
// Access tokens expire - check before API calls
const token = auth.getAccessToken();
if (!token) {
// Session expired, re-authenticate
auth.login();
}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 - Deprecated):
// ❌ No longer supported
await auth.login(email, password);
await auth.register(email, password);After (SDK 2.0):
// ✅ OAuth redirect
auth.login(); // Redirects to login.flowsta.com
const user = await auth.handleCallback();