Skip to content

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

bash
npm install @flowsta/auth

Basic Usage

typescript
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

PropertyTypeRequiredDefaultDescription
clientIdstring✅ Yes-Your application's client ID
redirectUristring✅ Yes-OAuth callback URL
scopesstring[]❌ No['profile', 'email']OAuth scopes to request
loginUrlstring❌ Nohttps://login.flowsta.comFlowsta login URL
apiUrlstring❌ Nohttps://auth-api.flowsta.comFlowsta API URL
typescript
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.

typescript
auth.login();
// User is redirected to login.flowsta.com
// After authentication, they're redirected back to your redirectUri

handleCallback()

Handle OAuth callback and retrieve user data. Call this on your redirect URI page.

typescript
const user = await auth.handleCallback();

// user contains:
// - id: string
// - email?: string
// - username?: string
// - displayName?: string
// - profilePicture?: string
// - agentPubKey?: string
// - did?: string

isAuthenticated()

Check if user is logged in.

typescript
if (auth.isAuthenticated()) {
  console.log('User is logged in');
}

getUser()

Get the current user.

typescript
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.

typescript
const token = auth.getAccessToken();

// Use for API requests
fetch('/api/data', {
  headers: { 'Authorization': `Bearer ${token}` }
});

logout()

Log out the current user.

typescript
auth.logout();
// Clears local session storage

getState()

Get the full authentication state.

typescript
const state = auth.getState();
// {
//   isAuthenticated: boolean,
//   user: FlowstaUser | null,
//   accessToken: string | null,
//   isLoading: boolean,
//   error: string | null
// }

Type Definitions

typescript
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:

tsx
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:

typescript
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:

  1. Generates a random code_verifier (128 characters)
  2. Creates a code_challenge (SHA-256 hash)
  3. Sends code_challenge with authorization request
  4. Sends code_verifier with token exchange

This prevents authorization code interception attacks without needing a client secret.

State Parameter

The SDK automatically:

  • Generates a random state parameter
  • 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

typescript
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

typescript
// On protected pages
if (!auth.isAuthenticated()) {
  // Redirect to login
  window.location.href = '/login';
}

3. Handle Token Expiration

typescript
// 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):

typescript
// ❌ No longer supported
await auth.login(email, password);
await auth.register(email, password);

After (SDK 2.0):

typescript
// ✅ OAuth redirect
auth.login(); // Redirects to login.flowsta.com
const user = await auth.handleCallback();

Next Steps

Documentation licensed under CC BY-SA 4.0.