@flowsta/auth 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,191 @@
1
+ # @flowsta/auth
2
+
3
+ Flowsta Auth SDK 2.0 - OAuth-only authentication for web applications.
4
+
5
+ ## Features
6
+
7
+ - 🔐 **OAuth 2.0 + PKCE** - Secure authentication without client secrets
8
+ - 🌐 **Zero-Knowledge** - Your users' data stays private
9
+ - ⚡ **Simple Integration** - Just a few lines of code
10
+ - 🎨 **Framework Support** - Vanilla JS, React, and more
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @flowsta/auth
16
+ # or
17
+ yarn add @flowsta/auth
18
+ # or
19
+ pnpm add @flowsta/auth
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ### 1. Create an App
25
+
26
+ Go to [dev.flowsta.com](https://dev.flowsta.com) and create an app to get your Client ID.
27
+
28
+ ### 2. Add the Login Button
29
+
30
+ ```typescript
31
+ import { FlowstaAuth } from '@flowsta/auth';
32
+
33
+ const auth = new FlowstaAuth({
34
+ clientId: 'your-client-id',
35
+ redirectUri: 'https://yoursite.com/auth/callback',
36
+ });
37
+
38
+ // Redirect to Flowsta login
39
+ document.getElementById('login-btn').onclick = () => auth.login();
40
+ ```
41
+
42
+ ### 3. Handle the Callback
43
+
44
+ On your redirect URI page (`/auth/callback`):
45
+
46
+ ```typescript
47
+ import { FlowstaAuth } from '@flowsta/auth';
48
+
49
+ const auth = new FlowstaAuth({
50
+ clientId: 'your-client-id',
51
+ redirectUri: 'https://yoursite.com/auth/callback',
52
+ });
53
+
54
+ // Handle the OAuth callback
55
+ try {
56
+ const user = await auth.handleCallback();
57
+ console.log('Logged in as:', user.email);
58
+ window.location.href = '/dashboard';
59
+ } catch (error) {
60
+ console.error('Login failed:', error.message);
61
+ }
62
+ ```
63
+
64
+ ### 4. Check Authentication Status
65
+
66
+ ```typescript
67
+ if (auth.isAuthenticated()) {
68
+ const user = auth.getUser();
69
+ console.log('Welcome,', user.displayName);
70
+ }
71
+ ```
72
+
73
+ ## React Integration
74
+
75
+ ```tsx
76
+ import { FlowstaAuthProvider, useFlowstaAuth } from '@flowsta/auth/react';
77
+
78
+ // Wrap your app
79
+ function App() {
80
+ return (
81
+ <FlowstaAuthProvider
82
+ clientId="your-client-id"
83
+ redirectUri="https://yoursite.com/auth/callback"
84
+ >
85
+ <MyApp />
86
+ </FlowstaAuthProvider>
87
+ );
88
+ }
89
+
90
+ // Use in components
91
+ function LoginButton() {
92
+ const { isAuthenticated, user, login, logout } = useFlowstaAuth();
93
+
94
+ if (isAuthenticated) {
95
+ return (
96
+ <div>
97
+ <span>Hello, {user.displayName}!</span>
98
+ <button onClick={logout}>Logout</button>
99
+ </div>
100
+ );
101
+ }
102
+
103
+ return <button onClick={login}>Sign in with Flowsta</button>;
104
+ }
105
+
106
+ // Callback page
107
+ function AuthCallback() {
108
+ const { handleCallback, isLoading, error } = useFlowstaAuth();
109
+
110
+ useEffect(() => {
111
+ handleCallback()
112
+ .then(() => window.location.href = '/dashboard')
113
+ .catch(console.error);
114
+ }, []);
115
+
116
+ if (isLoading) return <p>Logging in...</p>;
117
+ if (error) return <p>Error: {error}</p>;
118
+ return null;
119
+ }
120
+ ```
121
+
122
+ ## API Reference
123
+
124
+ ### FlowstaAuth
125
+
126
+ ```typescript
127
+ const auth = new FlowstaAuth({
128
+ clientId: string; // Required: Your app's client ID
129
+ redirectUri: string; // Required: OAuth callback URL
130
+ scopes?: string[]; // Optional: ['profile', 'email'] (default)
131
+ loginUrl?: string; // Optional: Flowsta login URL
132
+ apiUrl?: string; // Optional: Flowsta API URL
133
+ });
134
+ ```
135
+
136
+ #### Methods
137
+
138
+ | Method | Returns | Description |
139
+ |--------|---------|-------------|
140
+ | `login()` | `Promise<void>` | Redirect to Flowsta login |
141
+ | `handleCallback()` | `Promise<FlowstaUser>` | Handle OAuth callback |
142
+ | `logout()` | `void` | Log out the user |
143
+ | `isAuthenticated()` | `boolean` | Check if user is logged in |
144
+ | `getUser()` | `FlowstaUser \| null` | Get current user |
145
+ | `getAccessToken()` | `string \| null` | Get access token |
146
+ | `getState()` | `AuthState` | Get full auth state |
147
+
148
+ ### FlowstaUser
149
+
150
+ ```typescript
151
+ interface FlowstaUser {
152
+ id: string;
153
+ email?: string; // If 'email' scope was granted
154
+ username?: string; // User's username (if set)
155
+ displayName?: string; // Display name
156
+ profilePicture?: string; // Profile picture URL
157
+ agentPubKey?: string; // Holochain agent public key
158
+ did?: string; // Decentralized Identifier
159
+ }
160
+ ```
161
+
162
+ ## Security
163
+
164
+ This SDK uses **OAuth 2.0 Authorization Code Flow with PKCE**, which means:
165
+
166
+ - ✅ No client secrets needed (safe for browser/mobile apps)
167
+ - ✅ Authorization codes are protected by PKCE challenge
168
+ - ✅ State parameter prevents CSRF attacks
169
+ - ✅ Tokens are securely stored in localStorage
170
+
171
+ ## Migration from SDK 1.x
172
+
173
+ SDK 2.0 removes direct email/password authentication. All users now authenticate through Flowsta's hosted login page.
174
+
175
+ **Before (SDK 1.x):**
176
+ ```typescript
177
+ // ❌ Deprecated - do not use
178
+ await auth.login(email, password);
179
+ await auth.register(email, password);
180
+ ```
181
+
182
+ **After (SDK 2.0):**
183
+ ```typescript
184
+ // ✅ OAuth redirect
185
+ await auth.login(); // Redirects to login.flowsta.com
186
+ ```
187
+
188
+ ## License
189
+
190
+ MIT
191
+
@@ -0,0 +1,183 @@
1
+ // src/index.ts
2
+ async function generatePKCEPair() {
3
+ const verifier = generateRandomString(128);
4
+ const encoder = new TextEncoder();
5
+ const data = encoder.encode(verifier);
6
+ const digest = await crypto.subtle.digest("SHA-256", data);
7
+ const challenge = base64UrlEncode(digest);
8
+ return { verifier, challenge };
9
+ }
10
+ function generateRandomString(length) {
11
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
12
+ const array = new Uint8Array(length);
13
+ crypto.getRandomValues(array);
14
+ return Array.from(array, (byte) => chars[byte % chars.length]).join("");
15
+ }
16
+ function base64UrlEncode(buffer) {
17
+ const bytes = new Uint8Array(buffer);
18
+ let binary = "";
19
+ for (let i = 0; i < bytes.byteLength; i++) {
20
+ binary += String.fromCharCode(bytes[i]);
21
+ }
22
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
23
+ }
24
+ var FlowstaAuth = class {
25
+ constructor(config) {
26
+ this.accessToken = null;
27
+ this.user = null;
28
+ this.config = {
29
+ clientId: config.clientId,
30
+ redirectUri: config.redirectUri,
31
+ scopes: config.scopes || ["profile", "email"],
32
+ loginUrl: config.loginUrl || "https://login.flowsta.com",
33
+ apiUrl: config.apiUrl || "https://auth-api.flowsta.com"
34
+ };
35
+ this.restoreSession();
36
+ }
37
+ /**
38
+ * Redirect user to Flowsta login page
39
+ * User will be redirected back to redirectUri after authentication
40
+ */
41
+ async login() {
42
+ const { verifier, challenge } = await generatePKCEPair();
43
+ const state = generateRandomString(32);
44
+ sessionStorage.setItem("flowsta_code_verifier", verifier);
45
+ sessionStorage.setItem("flowsta_state", state);
46
+ const params = new URLSearchParams({
47
+ client_id: this.config.clientId,
48
+ redirect_uri: this.config.redirectUri,
49
+ response_type: "code",
50
+ scope: this.config.scopes.join(" "),
51
+ state,
52
+ code_challenge: challenge,
53
+ code_challenge_method: "S256"
54
+ });
55
+ window.location.href = `${this.config.loginUrl}/login?${params.toString()}`;
56
+ }
57
+ /**
58
+ * Handle OAuth callback after user authentication
59
+ * Call this on your redirect URI page
60
+ * @returns The authenticated user
61
+ */
62
+ async handleCallback() {
63
+ const params = new URLSearchParams(window.location.search);
64
+ const error = params.get("error");
65
+ if (error) {
66
+ const description = params.get("error_description") || error;
67
+ throw new Error(description);
68
+ }
69
+ const code = params.get("code");
70
+ if (!code) {
71
+ throw new Error("No authorization code received");
72
+ }
73
+ const state = params.get("state");
74
+ const storedState = sessionStorage.getItem("flowsta_state");
75
+ if (!state || state !== storedState) {
76
+ throw new Error("Invalid state parameter - possible CSRF attack");
77
+ }
78
+ const codeVerifier = sessionStorage.getItem("flowsta_code_verifier");
79
+ if (!codeVerifier) {
80
+ throw new Error("Missing PKCE code verifier");
81
+ }
82
+ const tokenResponse = await fetch(`${this.config.apiUrl}/oauth/token`, {
83
+ method: "POST",
84
+ headers: { "Content-Type": "application/json" },
85
+ body: JSON.stringify({
86
+ grant_type: "authorization_code",
87
+ code,
88
+ redirect_uri: this.config.redirectUri,
89
+ client_id: this.config.clientId,
90
+ code_verifier: codeVerifier
91
+ })
92
+ });
93
+ if (!tokenResponse.ok) {
94
+ const errorData = await tokenResponse.json();
95
+ throw new Error(errorData.error_description || "Token exchange failed");
96
+ }
97
+ const { access_token, refresh_token } = await tokenResponse.json();
98
+ sessionStorage.removeItem("flowsta_code_verifier");
99
+ sessionStorage.removeItem("flowsta_state");
100
+ const userResponse = await fetch(`${this.config.apiUrl}/oauth/userinfo`, {
101
+ headers: { "Authorization": `Bearer ${access_token}` }
102
+ });
103
+ if (!userResponse.ok) {
104
+ throw new Error("Failed to fetch user info");
105
+ }
106
+ const userData = await userResponse.json();
107
+ this.accessToken = access_token;
108
+ this.user = {
109
+ id: userData.sub || userData.id,
110
+ email: userData.email,
111
+ username: userData.preferred_username,
112
+ displayName: userData.display_name || userData.name,
113
+ profilePicture: userData.picture || userData.profile_picture,
114
+ agentPubKey: userData.agent_pub_key,
115
+ did: userData.did
116
+ };
117
+ localStorage.setItem("flowsta_access_token", access_token);
118
+ localStorage.setItem("flowsta_user", JSON.stringify(this.user));
119
+ if (refresh_token) {
120
+ localStorage.setItem("flowsta_refresh_token", refresh_token);
121
+ }
122
+ return this.user;
123
+ }
124
+ /**
125
+ * Log out the current user
126
+ */
127
+ logout() {
128
+ this.accessToken = null;
129
+ this.user = null;
130
+ localStorage.removeItem("flowsta_access_token");
131
+ localStorage.removeItem("flowsta_user");
132
+ localStorage.removeItem("flowsta_refresh_token");
133
+ }
134
+ /**
135
+ * Check if user is authenticated
136
+ */
137
+ isAuthenticated() {
138
+ return !!this.accessToken && !!this.user;
139
+ }
140
+ /**
141
+ * Get the current user
142
+ */
143
+ getUser() {
144
+ return this.user;
145
+ }
146
+ /**
147
+ * Get the current access token
148
+ */
149
+ getAccessToken() {
150
+ return this.accessToken;
151
+ }
152
+ /**
153
+ * Get current auth state
154
+ */
155
+ getState() {
156
+ return {
157
+ isAuthenticated: this.isAuthenticated(),
158
+ user: this.user,
159
+ accessToken: this.accessToken,
160
+ isLoading: false,
161
+ error: null
162
+ };
163
+ }
164
+ restoreSession() {
165
+ if (typeof localStorage === "undefined") return;
166
+ const token = localStorage.getItem("flowsta_access_token");
167
+ const userJson = localStorage.getItem("flowsta_user");
168
+ if (token && userJson) {
169
+ try {
170
+ this.accessToken = token;
171
+ this.user = JSON.parse(userJson);
172
+ } catch {
173
+ this.logout();
174
+ }
175
+ }
176
+ }
177
+ };
178
+ var index_default = FlowstaAuth;
179
+
180
+ export {
181
+ FlowstaAuth,
182
+ index_default
183
+ };
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Flowsta Auth SDK 2.0
3
+ *
4
+ * OAuth-only authentication for partner sites.
5
+ * All authentication flows through login.flowsta.com
6
+ *
7
+ * Features:
8
+ * - OAuth 2.0 Authorization Code Flow with PKCE
9
+ * - Zero-knowledge architecture
10
+ * - No client secrets needed (PKCE provides security)
11
+ * - Simple "Sign in with Flowsta" integration
12
+ */
13
+ interface FlowstaAuthConfig {
14
+ /** Your Flowsta application client ID (from dev.flowsta.com) */
15
+ clientId: string;
16
+ /** The URI to redirect back to after authentication */
17
+ redirectUri: string;
18
+ /** OAuth scopes to request. Default: ['profile', 'email'] */
19
+ scopes?: string[];
20
+ /** The Flowsta login URL. Default: 'https://login.flowsta.com' */
21
+ loginUrl?: string;
22
+ /** The Flowsta API URL. Default: 'https://auth-api.flowsta.com' */
23
+ apiUrl?: string;
24
+ }
25
+ interface FlowstaUser {
26
+ /** User's unique ID */
27
+ id: string;
28
+ /** User's email address (if 'email' scope was granted) */
29
+ email?: string;
30
+ /** User's username (if set) */
31
+ username?: string;
32
+ /** User's display name */
33
+ displayName?: string;
34
+ /** User's profile picture URL */
35
+ profilePicture?: string;
36
+ /** User's Holochain agent public key */
37
+ agentPubKey?: string;
38
+ /** User's DID (Decentralized Identifier) */
39
+ did?: string;
40
+ }
41
+ interface AuthState {
42
+ /** Whether the user is authenticated */
43
+ isAuthenticated: boolean;
44
+ /** The current user (null if not authenticated) */
45
+ user: FlowstaUser | null;
46
+ /** The access token (null if not authenticated) */
47
+ accessToken: string | null;
48
+ /** Whether authentication is loading */
49
+ isLoading: boolean;
50
+ /** Any authentication error */
51
+ error: string | null;
52
+ }
53
+ /**
54
+ * FlowstaAuth class - Main SDK entry point
55
+ *
56
+ * Usage:
57
+ * ```typescript
58
+ * const auth = new FlowstaAuth({
59
+ * clientId: 'your-client-id',
60
+ * redirectUri: 'https://yoursite.com/auth/callback'
61
+ * });
62
+ *
63
+ * // Redirect to login
64
+ * auth.login();
65
+ *
66
+ * // Handle callback (on your redirect URI page)
67
+ * await auth.handleCallback();
68
+ *
69
+ * // Get current user
70
+ * const user = auth.getUser();
71
+ * ```
72
+ */
73
+ declare class FlowstaAuth {
74
+ private config;
75
+ private accessToken;
76
+ private user;
77
+ constructor(config: FlowstaAuthConfig);
78
+ /**
79
+ * Redirect user to Flowsta login page
80
+ * User will be redirected back to redirectUri after authentication
81
+ */
82
+ login(): Promise<void>;
83
+ /**
84
+ * Handle OAuth callback after user authentication
85
+ * Call this on your redirect URI page
86
+ * @returns The authenticated user
87
+ */
88
+ handleCallback(): Promise<FlowstaUser>;
89
+ /**
90
+ * Log out the current user
91
+ */
92
+ logout(): void;
93
+ /**
94
+ * Check if user is authenticated
95
+ */
96
+ isAuthenticated(): boolean;
97
+ /**
98
+ * Get the current user
99
+ */
100
+ getUser(): FlowstaUser | null;
101
+ /**
102
+ * Get the current access token
103
+ */
104
+ getAccessToken(): string | null;
105
+ /**
106
+ * Get current auth state
107
+ */
108
+ getState(): AuthState;
109
+ private restoreSession;
110
+ }
111
+
112
+ export { type AuthState, FlowstaAuth, type FlowstaAuthConfig, type FlowstaUser, FlowstaAuth as default };
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Flowsta Auth SDK 2.0
3
+ *
4
+ * OAuth-only authentication for partner sites.
5
+ * All authentication flows through login.flowsta.com
6
+ *
7
+ * Features:
8
+ * - OAuth 2.0 Authorization Code Flow with PKCE
9
+ * - Zero-knowledge architecture
10
+ * - No client secrets needed (PKCE provides security)
11
+ * - Simple "Sign in with Flowsta" integration
12
+ */
13
+ interface FlowstaAuthConfig {
14
+ /** Your Flowsta application client ID (from dev.flowsta.com) */
15
+ clientId: string;
16
+ /** The URI to redirect back to after authentication */
17
+ redirectUri: string;
18
+ /** OAuth scopes to request. Default: ['profile', 'email'] */
19
+ scopes?: string[];
20
+ /** The Flowsta login URL. Default: 'https://login.flowsta.com' */
21
+ loginUrl?: string;
22
+ /** The Flowsta API URL. Default: 'https://auth-api.flowsta.com' */
23
+ apiUrl?: string;
24
+ }
25
+ interface FlowstaUser {
26
+ /** User's unique ID */
27
+ id: string;
28
+ /** User's email address (if 'email' scope was granted) */
29
+ email?: string;
30
+ /** User's username (if set) */
31
+ username?: string;
32
+ /** User's display name */
33
+ displayName?: string;
34
+ /** User's profile picture URL */
35
+ profilePicture?: string;
36
+ /** User's Holochain agent public key */
37
+ agentPubKey?: string;
38
+ /** User's DID (Decentralized Identifier) */
39
+ did?: string;
40
+ }
41
+ interface AuthState {
42
+ /** Whether the user is authenticated */
43
+ isAuthenticated: boolean;
44
+ /** The current user (null if not authenticated) */
45
+ user: FlowstaUser | null;
46
+ /** The access token (null if not authenticated) */
47
+ accessToken: string | null;
48
+ /** Whether authentication is loading */
49
+ isLoading: boolean;
50
+ /** Any authentication error */
51
+ error: string | null;
52
+ }
53
+ /**
54
+ * FlowstaAuth class - Main SDK entry point
55
+ *
56
+ * Usage:
57
+ * ```typescript
58
+ * const auth = new FlowstaAuth({
59
+ * clientId: 'your-client-id',
60
+ * redirectUri: 'https://yoursite.com/auth/callback'
61
+ * });
62
+ *
63
+ * // Redirect to login
64
+ * auth.login();
65
+ *
66
+ * // Handle callback (on your redirect URI page)
67
+ * await auth.handleCallback();
68
+ *
69
+ * // Get current user
70
+ * const user = auth.getUser();
71
+ * ```
72
+ */
73
+ declare class FlowstaAuth {
74
+ private config;
75
+ private accessToken;
76
+ private user;
77
+ constructor(config: FlowstaAuthConfig);
78
+ /**
79
+ * Redirect user to Flowsta login page
80
+ * User will be redirected back to redirectUri after authentication
81
+ */
82
+ login(): Promise<void>;
83
+ /**
84
+ * Handle OAuth callback after user authentication
85
+ * Call this on your redirect URI page
86
+ * @returns The authenticated user
87
+ */
88
+ handleCallback(): Promise<FlowstaUser>;
89
+ /**
90
+ * Log out the current user
91
+ */
92
+ logout(): void;
93
+ /**
94
+ * Check if user is authenticated
95
+ */
96
+ isAuthenticated(): boolean;
97
+ /**
98
+ * Get the current user
99
+ */
100
+ getUser(): FlowstaUser | null;
101
+ /**
102
+ * Get the current access token
103
+ */
104
+ getAccessToken(): string | null;
105
+ /**
106
+ * Get current auth state
107
+ */
108
+ getState(): AuthState;
109
+ private restoreSession;
110
+ }
111
+
112
+ export { type AuthState, FlowstaAuth, type FlowstaAuthConfig, type FlowstaUser, FlowstaAuth as default };
package/dist/index.js ADDED
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ FlowstaAuth: () => FlowstaAuth,
24
+ default: () => index_default
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+ async function generatePKCEPair() {
28
+ const verifier = generateRandomString(128);
29
+ const encoder = new TextEncoder();
30
+ const data = encoder.encode(verifier);
31
+ const digest = await crypto.subtle.digest("SHA-256", data);
32
+ const challenge = base64UrlEncode(digest);
33
+ return { verifier, challenge };
34
+ }
35
+ function generateRandomString(length) {
36
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
37
+ const array = new Uint8Array(length);
38
+ crypto.getRandomValues(array);
39
+ return Array.from(array, (byte) => chars[byte % chars.length]).join("");
40
+ }
41
+ function base64UrlEncode(buffer) {
42
+ const bytes = new Uint8Array(buffer);
43
+ let binary = "";
44
+ for (let i = 0; i < bytes.byteLength; i++) {
45
+ binary += String.fromCharCode(bytes[i]);
46
+ }
47
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
48
+ }
49
+ var FlowstaAuth = class {
50
+ constructor(config) {
51
+ this.accessToken = null;
52
+ this.user = null;
53
+ this.config = {
54
+ clientId: config.clientId,
55
+ redirectUri: config.redirectUri,
56
+ scopes: config.scopes || ["profile", "email"],
57
+ loginUrl: config.loginUrl || "https://login.flowsta.com",
58
+ apiUrl: config.apiUrl || "https://auth-api.flowsta.com"
59
+ };
60
+ this.restoreSession();
61
+ }
62
+ /**
63
+ * Redirect user to Flowsta login page
64
+ * User will be redirected back to redirectUri after authentication
65
+ */
66
+ async login() {
67
+ const { verifier, challenge } = await generatePKCEPair();
68
+ const state = generateRandomString(32);
69
+ sessionStorage.setItem("flowsta_code_verifier", verifier);
70
+ sessionStorage.setItem("flowsta_state", state);
71
+ const params = new URLSearchParams({
72
+ client_id: this.config.clientId,
73
+ redirect_uri: this.config.redirectUri,
74
+ response_type: "code",
75
+ scope: this.config.scopes.join(" "),
76
+ state,
77
+ code_challenge: challenge,
78
+ code_challenge_method: "S256"
79
+ });
80
+ window.location.href = `${this.config.loginUrl}/login?${params.toString()}`;
81
+ }
82
+ /**
83
+ * Handle OAuth callback after user authentication
84
+ * Call this on your redirect URI page
85
+ * @returns The authenticated user
86
+ */
87
+ async handleCallback() {
88
+ const params = new URLSearchParams(window.location.search);
89
+ const error = params.get("error");
90
+ if (error) {
91
+ const description = params.get("error_description") || error;
92
+ throw new Error(description);
93
+ }
94
+ const code = params.get("code");
95
+ if (!code) {
96
+ throw new Error("No authorization code received");
97
+ }
98
+ const state = params.get("state");
99
+ const storedState = sessionStorage.getItem("flowsta_state");
100
+ if (!state || state !== storedState) {
101
+ throw new Error("Invalid state parameter - possible CSRF attack");
102
+ }
103
+ const codeVerifier = sessionStorage.getItem("flowsta_code_verifier");
104
+ if (!codeVerifier) {
105
+ throw new Error("Missing PKCE code verifier");
106
+ }
107
+ const tokenResponse = await fetch(`${this.config.apiUrl}/oauth/token`, {
108
+ method: "POST",
109
+ headers: { "Content-Type": "application/json" },
110
+ body: JSON.stringify({
111
+ grant_type: "authorization_code",
112
+ code,
113
+ redirect_uri: this.config.redirectUri,
114
+ client_id: this.config.clientId,
115
+ code_verifier: codeVerifier
116
+ })
117
+ });
118
+ if (!tokenResponse.ok) {
119
+ const errorData = await tokenResponse.json();
120
+ throw new Error(errorData.error_description || "Token exchange failed");
121
+ }
122
+ const { access_token, refresh_token } = await tokenResponse.json();
123
+ sessionStorage.removeItem("flowsta_code_verifier");
124
+ sessionStorage.removeItem("flowsta_state");
125
+ const userResponse = await fetch(`${this.config.apiUrl}/oauth/userinfo`, {
126
+ headers: { "Authorization": `Bearer ${access_token}` }
127
+ });
128
+ if (!userResponse.ok) {
129
+ throw new Error("Failed to fetch user info");
130
+ }
131
+ const userData = await userResponse.json();
132
+ this.accessToken = access_token;
133
+ this.user = {
134
+ id: userData.sub || userData.id,
135
+ email: userData.email,
136
+ username: userData.preferred_username,
137
+ displayName: userData.display_name || userData.name,
138
+ profilePicture: userData.picture || userData.profile_picture,
139
+ agentPubKey: userData.agent_pub_key,
140
+ did: userData.did
141
+ };
142
+ localStorage.setItem("flowsta_access_token", access_token);
143
+ localStorage.setItem("flowsta_user", JSON.stringify(this.user));
144
+ if (refresh_token) {
145
+ localStorage.setItem("flowsta_refresh_token", refresh_token);
146
+ }
147
+ return this.user;
148
+ }
149
+ /**
150
+ * Log out the current user
151
+ */
152
+ logout() {
153
+ this.accessToken = null;
154
+ this.user = null;
155
+ localStorage.removeItem("flowsta_access_token");
156
+ localStorage.removeItem("flowsta_user");
157
+ localStorage.removeItem("flowsta_refresh_token");
158
+ }
159
+ /**
160
+ * Check if user is authenticated
161
+ */
162
+ isAuthenticated() {
163
+ return !!this.accessToken && !!this.user;
164
+ }
165
+ /**
166
+ * Get the current user
167
+ */
168
+ getUser() {
169
+ return this.user;
170
+ }
171
+ /**
172
+ * Get the current access token
173
+ */
174
+ getAccessToken() {
175
+ return this.accessToken;
176
+ }
177
+ /**
178
+ * Get current auth state
179
+ */
180
+ getState() {
181
+ return {
182
+ isAuthenticated: this.isAuthenticated(),
183
+ user: this.user,
184
+ accessToken: this.accessToken,
185
+ isLoading: false,
186
+ error: null
187
+ };
188
+ }
189
+ restoreSession() {
190
+ if (typeof localStorage === "undefined") return;
191
+ const token = localStorage.getItem("flowsta_access_token");
192
+ const userJson = localStorage.getItem("flowsta_user");
193
+ if (token && userJson) {
194
+ try {
195
+ this.accessToken = token;
196
+ this.user = JSON.parse(userJson);
197
+ } catch {
198
+ this.logout();
199
+ }
200
+ }
201
+ }
202
+ };
203
+ var index_default = FlowstaAuth;
204
+ // Annotate the CommonJS export names for ESM import in node:
205
+ 0 && (module.exports = {
206
+ FlowstaAuth
207
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,8 @@
1
+ import {
2
+ FlowstaAuth,
3
+ index_default
4
+ } from "./chunk-NBWAVXMK.mjs";
5
+ export {
6
+ FlowstaAuth,
7
+ index_default as default
8
+ };
@@ -0,0 +1,37 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { FlowstaAuthConfig, AuthState, FlowstaUser } from './index.mjs';
4
+ export { default as FlowstaAuth } from './index.mjs';
5
+
6
+ interface FlowstaAuthContextValue extends AuthState {
7
+ /** Redirect to Flowsta login */
8
+ login: () => Promise<void>;
9
+ /** Log out the current user */
10
+ logout: () => void;
11
+ /** Handle OAuth callback (call on redirect URI page) */
12
+ handleCallback: () => Promise<FlowstaUser>;
13
+ }
14
+ interface FlowstaAuthProviderProps extends FlowstaAuthConfig {
15
+ children: ReactNode;
16
+ }
17
+ /**
18
+ * Flowsta Auth Provider component
19
+ * Wrap your app with this to enable authentication
20
+ */
21
+ declare function FlowstaAuthProvider({ children, clientId, redirectUri, scopes, loginUrl, apiUrl, }: FlowstaAuthProviderProps): react_jsx_runtime.JSX.Element;
22
+ /**
23
+ * Hook to access Flowsta Auth
24
+ * Must be used within a FlowstaAuthProvider
25
+ */
26
+ declare function useFlowstaAuth(): FlowstaAuthContextValue;
27
+ /**
28
+ * Hook to protect routes/components
29
+ * Redirects to login if not authenticated
30
+ */
31
+ declare function useRequireAuth(options?: {
32
+ redirectTo?: string;
33
+ }): AuthState & {
34
+ isReady: boolean;
35
+ };
36
+
37
+ export { AuthState, FlowstaAuthConfig, FlowstaAuthProvider, FlowstaUser, FlowstaAuthProvider as default, useFlowstaAuth, useRequireAuth };
@@ -0,0 +1,37 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { FlowstaAuthConfig, AuthState, FlowstaUser } from './index.js';
4
+ export { default as FlowstaAuth } from './index.js';
5
+
6
+ interface FlowstaAuthContextValue extends AuthState {
7
+ /** Redirect to Flowsta login */
8
+ login: () => Promise<void>;
9
+ /** Log out the current user */
10
+ logout: () => void;
11
+ /** Handle OAuth callback (call on redirect URI page) */
12
+ handleCallback: () => Promise<FlowstaUser>;
13
+ }
14
+ interface FlowstaAuthProviderProps extends FlowstaAuthConfig {
15
+ children: ReactNode;
16
+ }
17
+ /**
18
+ * Flowsta Auth Provider component
19
+ * Wrap your app with this to enable authentication
20
+ */
21
+ declare function FlowstaAuthProvider({ children, clientId, redirectUri, scopes, loginUrl, apiUrl, }: FlowstaAuthProviderProps): react_jsx_runtime.JSX.Element;
22
+ /**
23
+ * Hook to access Flowsta Auth
24
+ * Must be used within a FlowstaAuthProvider
25
+ */
26
+ declare function useFlowstaAuth(): FlowstaAuthContextValue;
27
+ /**
28
+ * Hook to protect routes/components
29
+ * Redirects to login if not authenticated
30
+ */
31
+ declare function useRequireAuth(options?: {
32
+ redirectTo?: string;
33
+ }): AuthState & {
34
+ isReady: boolean;
35
+ };
36
+
37
+ export { AuthState, FlowstaAuthConfig, FlowstaAuthProvider, FlowstaUser, FlowstaAuthProvider as default, useFlowstaAuth, useRequireAuth };
package/dist/react.js ADDED
@@ -0,0 +1,316 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/react.tsx
21
+ var react_exports = {};
22
+ __export(react_exports, {
23
+ FlowstaAuth: () => FlowstaAuth,
24
+ FlowstaAuthProvider: () => FlowstaAuthProvider,
25
+ default: () => react_default,
26
+ useFlowstaAuth: () => useFlowstaAuth,
27
+ useRequireAuth: () => useRequireAuth
28
+ });
29
+ module.exports = __toCommonJS(react_exports);
30
+ var import_react = require("react");
31
+
32
+ // src/index.ts
33
+ async function generatePKCEPair() {
34
+ const verifier = generateRandomString(128);
35
+ const encoder = new TextEncoder();
36
+ const data = encoder.encode(verifier);
37
+ const digest = await crypto.subtle.digest("SHA-256", data);
38
+ const challenge = base64UrlEncode(digest);
39
+ return { verifier, challenge };
40
+ }
41
+ function generateRandomString(length) {
42
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
43
+ const array = new Uint8Array(length);
44
+ crypto.getRandomValues(array);
45
+ return Array.from(array, (byte) => chars[byte % chars.length]).join("");
46
+ }
47
+ function base64UrlEncode(buffer) {
48
+ const bytes = new Uint8Array(buffer);
49
+ let binary = "";
50
+ for (let i = 0; i < bytes.byteLength; i++) {
51
+ binary += String.fromCharCode(bytes[i]);
52
+ }
53
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
54
+ }
55
+ var FlowstaAuth = class {
56
+ constructor(config) {
57
+ this.accessToken = null;
58
+ this.user = null;
59
+ this.config = {
60
+ clientId: config.clientId,
61
+ redirectUri: config.redirectUri,
62
+ scopes: config.scopes || ["profile", "email"],
63
+ loginUrl: config.loginUrl || "https://login.flowsta.com",
64
+ apiUrl: config.apiUrl || "https://auth-api.flowsta.com"
65
+ };
66
+ this.restoreSession();
67
+ }
68
+ /**
69
+ * Redirect user to Flowsta login page
70
+ * User will be redirected back to redirectUri after authentication
71
+ */
72
+ async login() {
73
+ const { verifier, challenge } = await generatePKCEPair();
74
+ const state = generateRandomString(32);
75
+ sessionStorage.setItem("flowsta_code_verifier", verifier);
76
+ sessionStorage.setItem("flowsta_state", state);
77
+ const params = new URLSearchParams({
78
+ client_id: this.config.clientId,
79
+ redirect_uri: this.config.redirectUri,
80
+ response_type: "code",
81
+ scope: this.config.scopes.join(" "),
82
+ state,
83
+ code_challenge: challenge,
84
+ code_challenge_method: "S256"
85
+ });
86
+ window.location.href = `${this.config.loginUrl}/login?${params.toString()}`;
87
+ }
88
+ /**
89
+ * Handle OAuth callback after user authentication
90
+ * Call this on your redirect URI page
91
+ * @returns The authenticated user
92
+ */
93
+ async handleCallback() {
94
+ const params = new URLSearchParams(window.location.search);
95
+ const error = params.get("error");
96
+ if (error) {
97
+ const description = params.get("error_description") || error;
98
+ throw new Error(description);
99
+ }
100
+ const code = params.get("code");
101
+ if (!code) {
102
+ throw new Error("No authorization code received");
103
+ }
104
+ const state = params.get("state");
105
+ const storedState = sessionStorage.getItem("flowsta_state");
106
+ if (!state || state !== storedState) {
107
+ throw new Error("Invalid state parameter - possible CSRF attack");
108
+ }
109
+ const codeVerifier = sessionStorage.getItem("flowsta_code_verifier");
110
+ if (!codeVerifier) {
111
+ throw new Error("Missing PKCE code verifier");
112
+ }
113
+ const tokenResponse = await fetch(`${this.config.apiUrl}/oauth/token`, {
114
+ method: "POST",
115
+ headers: { "Content-Type": "application/json" },
116
+ body: JSON.stringify({
117
+ grant_type: "authorization_code",
118
+ code,
119
+ redirect_uri: this.config.redirectUri,
120
+ client_id: this.config.clientId,
121
+ code_verifier: codeVerifier
122
+ })
123
+ });
124
+ if (!tokenResponse.ok) {
125
+ const errorData = await tokenResponse.json();
126
+ throw new Error(errorData.error_description || "Token exchange failed");
127
+ }
128
+ const { access_token, refresh_token } = await tokenResponse.json();
129
+ sessionStorage.removeItem("flowsta_code_verifier");
130
+ sessionStorage.removeItem("flowsta_state");
131
+ const userResponse = await fetch(`${this.config.apiUrl}/oauth/userinfo`, {
132
+ headers: { "Authorization": `Bearer ${access_token}` }
133
+ });
134
+ if (!userResponse.ok) {
135
+ throw new Error("Failed to fetch user info");
136
+ }
137
+ const userData = await userResponse.json();
138
+ this.accessToken = access_token;
139
+ this.user = {
140
+ id: userData.sub || userData.id,
141
+ email: userData.email,
142
+ username: userData.preferred_username,
143
+ displayName: userData.display_name || userData.name,
144
+ profilePicture: userData.picture || userData.profile_picture,
145
+ agentPubKey: userData.agent_pub_key,
146
+ did: userData.did
147
+ };
148
+ localStorage.setItem("flowsta_access_token", access_token);
149
+ localStorage.setItem("flowsta_user", JSON.stringify(this.user));
150
+ if (refresh_token) {
151
+ localStorage.setItem("flowsta_refresh_token", refresh_token);
152
+ }
153
+ return this.user;
154
+ }
155
+ /**
156
+ * Log out the current user
157
+ */
158
+ logout() {
159
+ this.accessToken = null;
160
+ this.user = null;
161
+ localStorage.removeItem("flowsta_access_token");
162
+ localStorage.removeItem("flowsta_user");
163
+ localStorage.removeItem("flowsta_refresh_token");
164
+ }
165
+ /**
166
+ * Check if user is authenticated
167
+ */
168
+ isAuthenticated() {
169
+ return !!this.accessToken && !!this.user;
170
+ }
171
+ /**
172
+ * Get the current user
173
+ */
174
+ getUser() {
175
+ return this.user;
176
+ }
177
+ /**
178
+ * Get the current access token
179
+ */
180
+ getAccessToken() {
181
+ return this.accessToken;
182
+ }
183
+ /**
184
+ * Get current auth state
185
+ */
186
+ getState() {
187
+ return {
188
+ isAuthenticated: this.isAuthenticated(),
189
+ user: this.user,
190
+ accessToken: this.accessToken,
191
+ isLoading: false,
192
+ error: null
193
+ };
194
+ }
195
+ restoreSession() {
196
+ if (typeof localStorage === "undefined") return;
197
+ const token = localStorage.getItem("flowsta_access_token");
198
+ const userJson = localStorage.getItem("flowsta_user");
199
+ if (token && userJson) {
200
+ try {
201
+ this.accessToken = token;
202
+ this.user = JSON.parse(userJson);
203
+ } catch {
204
+ this.logout();
205
+ }
206
+ }
207
+ }
208
+ };
209
+
210
+ // src/react.tsx
211
+ var import_jsx_runtime = require("react/jsx-runtime");
212
+ var FlowstaAuthContext = (0, import_react.createContext)(null);
213
+ function FlowstaAuthProvider({
214
+ children,
215
+ clientId,
216
+ redirectUri,
217
+ scopes,
218
+ loginUrl,
219
+ apiUrl
220
+ }) {
221
+ const [auth] = (0, import_react.useState)(() => new FlowstaAuth({
222
+ clientId,
223
+ redirectUri,
224
+ scopes,
225
+ loginUrl,
226
+ apiUrl
227
+ }));
228
+ const [state, setState] = (0, import_react.useState)(() => auth.getState());
229
+ (0, import_react.useEffect)(() => {
230
+ setState(auth.getState());
231
+ }, [auth]);
232
+ const login = (0, import_react.useCallback)(async () => {
233
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
234
+ try {
235
+ await auth.login();
236
+ } catch (error) {
237
+ setState((prev) => ({
238
+ ...prev,
239
+ isLoading: false,
240
+ error: error instanceof Error ? error.message : "Login failed"
241
+ }));
242
+ }
243
+ }, [auth]);
244
+ const logout = (0, import_react.useCallback)(() => {
245
+ auth.logout();
246
+ setState({
247
+ isAuthenticated: false,
248
+ user: null,
249
+ accessToken: null,
250
+ isLoading: false,
251
+ error: null
252
+ });
253
+ }, [auth]);
254
+ const handleCallback = (0, import_react.useCallback)(async () => {
255
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
256
+ try {
257
+ const user = await auth.handleCallback();
258
+ setState({
259
+ isAuthenticated: true,
260
+ user,
261
+ accessToken: auth.getAccessToken(),
262
+ isLoading: false,
263
+ error: null
264
+ });
265
+ return user;
266
+ } catch (error) {
267
+ const errorMessage = error instanceof Error ? error.message : "Authentication failed";
268
+ setState((prev) => ({
269
+ ...prev,
270
+ isLoading: false,
271
+ error: errorMessage
272
+ }));
273
+ throw error;
274
+ }
275
+ }, [auth]);
276
+ const value = {
277
+ ...state,
278
+ login,
279
+ logout,
280
+ handleCallback
281
+ };
282
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FlowstaAuthContext.Provider, { value, children });
283
+ }
284
+ function useFlowstaAuth() {
285
+ const context = (0, import_react.useContext)(FlowstaAuthContext);
286
+ if (!context) {
287
+ throw new Error("useFlowstaAuth must be used within a FlowstaAuthProvider");
288
+ }
289
+ return context;
290
+ }
291
+ function useRequireAuth(options) {
292
+ const { isAuthenticated, isLoading, login, ...rest } = useFlowstaAuth();
293
+ const [isReady, setIsReady] = (0, import_react.useState)(false);
294
+ (0, import_react.useEffect)(() => {
295
+ if (!isLoading) {
296
+ if (!isAuthenticated) {
297
+ if (options?.redirectTo) {
298
+ window.location.href = options.redirectTo;
299
+ } else {
300
+ login();
301
+ }
302
+ } else {
303
+ setIsReady(true);
304
+ }
305
+ }
306
+ }, [isAuthenticated, isLoading, login, options?.redirectTo]);
307
+ return { isAuthenticated, isLoading, isReady, ...rest };
308
+ }
309
+ var react_default = FlowstaAuthProvider;
310
+ // Annotate the CommonJS export names for ESM import in node:
311
+ 0 && (module.exports = {
312
+ FlowstaAuth,
313
+ FlowstaAuthProvider,
314
+ useFlowstaAuth,
315
+ useRequireAuth
316
+ });
package/dist/react.mjs ADDED
@@ -0,0 +1,118 @@
1
+ import {
2
+ FlowstaAuth
3
+ } from "./chunk-NBWAVXMK.mjs";
4
+
5
+ // src/react.tsx
6
+ import {
7
+ createContext,
8
+ useContext,
9
+ useState,
10
+ useEffect,
11
+ useCallback
12
+ } from "react";
13
+ import { jsx } from "react/jsx-runtime";
14
+ var FlowstaAuthContext = createContext(null);
15
+ function FlowstaAuthProvider({
16
+ children,
17
+ clientId,
18
+ redirectUri,
19
+ scopes,
20
+ loginUrl,
21
+ apiUrl
22
+ }) {
23
+ const [auth] = useState(() => new FlowstaAuth({
24
+ clientId,
25
+ redirectUri,
26
+ scopes,
27
+ loginUrl,
28
+ apiUrl
29
+ }));
30
+ const [state, setState] = useState(() => auth.getState());
31
+ useEffect(() => {
32
+ setState(auth.getState());
33
+ }, [auth]);
34
+ const login = useCallback(async () => {
35
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
36
+ try {
37
+ await auth.login();
38
+ } catch (error) {
39
+ setState((prev) => ({
40
+ ...prev,
41
+ isLoading: false,
42
+ error: error instanceof Error ? error.message : "Login failed"
43
+ }));
44
+ }
45
+ }, [auth]);
46
+ const logout = useCallback(() => {
47
+ auth.logout();
48
+ setState({
49
+ isAuthenticated: false,
50
+ user: null,
51
+ accessToken: null,
52
+ isLoading: false,
53
+ error: null
54
+ });
55
+ }, [auth]);
56
+ const handleCallback = useCallback(async () => {
57
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
58
+ try {
59
+ const user = await auth.handleCallback();
60
+ setState({
61
+ isAuthenticated: true,
62
+ user,
63
+ accessToken: auth.getAccessToken(),
64
+ isLoading: false,
65
+ error: null
66
+ });
67
+ return user;
68
+ } catch (error) {
69
+ const errorMessage = error instanceof Error ? error.message : "Authentication failed";
70
+ setState((prev) => ({
71
+ ...prev,
72
+ isLoading: false,
73
+ error: errorMessage
74
+ }));
75
+ throw error;
76
+ }
77
+ }, [auth]);
78
+ const value = {
79
+ ...state,
80
+ login,
81
+ logout,
82
+ handleCallback
83
+ };
84
+ return /* @__PURE__ */ jsx(FlowstaAuthContext.Provider, { value, children });
85
+ }
86
+ function useFlowstaAuth() {
87
+ const context = useContext(FlowstaAuthContext);
88
+ if (!context) {
89
+ throw new Error("useFlowstaAuth must be used within a FlowstaAuthProvider");
90
+ }
91
+ return context;
92
+ }
93
+ function useRequireAuth(options) {
94
+ const { isAuthenticated, isLoading, login, ...rest } = useFlowstaAuth();
95
+ const [isReady, setIsReady] = useState(false);
96
+ useEffect(() => {
97
+ if (!isLoading) {
98
+ if (!isAuthenticated) {
99
+ if (options?.redirectTo) {
100
+ window.location.href = options.redirectTo;
101
+ } else {
102
+ login();
103
+ }
104
+ } else {
105
+ setIsReady(true);
106
+ }
107
+ }
108
+ }, [isAuthenticated, isLoading, login, options?.redirectTo]);
109
+ return { isAuthenticated, isLoading, isReady, ...rest };
110
+ }
111
+ var react_default = FlowstaAuthProvider;
112
+ export {
113
+ FlowstaAuth,
114
+ FlowstaAuthProvider,
115
+ react_default as default,
116
+ useFlowstaAuth,
117
+ useRequireAuth
118
+ };
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@flowsta/auth",
3
+ "version": "2.0.0",
4
+ "description": "Flowsta Auth SDK 2.0 - OAuth-only authentication for web applications",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ },
14
+ "./react": {
15
+ "types": "./dist/react.d.ts",
16
+ "import": "./dist/react.mjs",
17
+ "require": "./dist/react.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsup src/index.ts src/react.tsx --format cjs,esm --dts",
25
+ "dev": "tsup src/index.ts src/react.tsx --format cjs,esm --dts --watch",
26
+ "test": "vitest",
27
+ "lint": "eslint src"
28
+ },
29
+ "keywords": [
30
+ "flowsta",
31
+ "auth",
32
+ "authentication",
33
+ "oauth",
34
+ "sso",
35
+ "pkce",
36
+ "zero-knowledge"
37
+ ],
38
+ "author": "Flowsta",
39
+ "license": "MIT",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/WeAreFlowsta/flowsta-sdk.git",
43
+ "directory": "packages/auth"
44
+ },
45
+ "peerDependencies": {
46
+ "react": ">=17.0.0"
47
+ },
48
+ "peerDependenciesMeta": {
49
+ "react": {
50
+ "optional": true
51
+ }
52
+ },
53
+ "devDependencies": {
54
+ "tsup": "^8.0.0",
55
+ "typescript": "^5.3.0",
56
+ "vitest": "^1.0.0",
57
+ "@types/react": "^18.2.0"
58
+ }
59
+ }
60
+