@faable/auth-js 1.6.1 → 1.6.2-next.2
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 +220 -17
- package/dist/dts/Base.d.ts +1 -1
- package/dist/dts/FaableAuthApi.d.ts +2 -2
- package/dist/dts/FaableAuthClient.d.ts +33 -24
- package/dist/dts/createClient.d.ts +2 -2
- package/dist/dts/entry.d.ts +7 -0
- package/dist/dts/entrypoints/faableauth.d.ts +1 -5
- package/dist/dts/entrypoints/main.es.d.ts +1 -5
- package/dist/dts/lib/auth_helpers.d.ts +16 -0
- package/dist/dts/lib/broadcast_sync.d.ts +22 -0
- package/dist/dts/lib/constants.d.ts +1 -2
- package/dist/dts/lib/errors.d.ts +1 -1
- package/dist/dts/lib/helpers.d.ts +4 -4
- package/dist/dts/lib/nextjs.d.ts +1 -1
- package/dist/dts/lib/pkce_storage.d.ts +15 -0
- package/dist/dts/lib/session_helpers.d.ts +7 -0
- package/dist/dts/lib/storage/cookie-storage.d.ts +17 -11
- package/dist/dts/lib/storage/cookie_helpers.d.ts +25 -0
- package/dist/dts/lib/storage/local-storage.d.ts +1 -1
- package/dist/dts/lib/storage_helpers.d.ts +1 -1
- package/dist/dts/lib/types.d.ts +33 -19
- package/dist/dts/lib/with_timeout.d.ts +7 -0
- package/dist/dts/lock/Lock.d.ts +3 -3
- package/dist/dts/lock/locks.d.ts +3 -3
- package/dist/dts/utils.d.ts +1 -1
- package/dist/faableauth.js +2 -2
- package/dist/faableauth.js.map +1 -1
- package/dist/main.js +2 -2
- package/dist/main.js.map +1 -1
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<a href="https://faable.com">
|
|
10
10
|
<h1 align="center">auth-js</h1>
|
|
11
11
|
</a>
|
|
12
|
-
<p align="center">An isomorphic
|
|
12
|
+
<p align="center">An isomorphic JavaScript client for Faable Auth.</p>
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
15
|
<p align="center">
|
|
@@ -18,33 +18,236 @@
|
|
|
18
18
|
</a>
|
|
19
19
|
</p>
|
|
20
20
|
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- OAuth social connections (Google, GitHub, …) with PKCE and implicit flows
|
|
24
|
+
- Username + password login
|
|
25
|
+
- Passwordless: email magic link and OTP code
|
|
26
|
+
- Automatic token refresh with cross-tab synchronization via `BroadcastChannel`
|
|
27
|
+
- Pluggable storage adapters (`localStorage`, cookies, or custom)
|
|
28
|
+
- Server-side session helpers for Next.js
|
|
29
|
+
|
|
21
30
|
## Install
|
|
22
31
|
|
|
23
32
|
```bash
|
|
24
|
-
|
|
33
|
+
npm install @faable/auth-js
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Requires Node.js `>=22.8` for development. The published bundle runs in any
|
|
37
|
+
modern browser and in Node/SSR environments.
|
|
38
|
+
|
|
39
|
+
## Quick start
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { createClient } from '@faable/auth-js'
|
|
43
|
+
|
|
44
|
+
export const auth = createClient({
|
|
45
|
+
domain: '<faableauth_domain>',
|
|
46
|
+
clientId: '<client_id>',
|
|
47
|
+
redirectUri: window.location.origin
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// Trigger a social login
|
|
51
|
+
await auth.signInWithOauthConnection({ connection: 'google' })
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Configuration
|
|
55
|
+
|
|
56
|
+
`createClient(config)` accepts:
|
|
57
|
+
|
|
58
|
+
| Option | Type | Description |
|
|
59
|
+
| --------------- | ------------------ | --------------------------------------------------------------------- |
|
|
60
|
+
| `domain` | `string` | **Required.** Your Faable Auth tenant domain. |
|
|
61
|
+
| `clientId` | `string` | **Required.** Application client ID. |
|
|
62
|
+
| `redirectUri` | `string` | Default callback URL. Falls back to `window.location.origin`. |
|
|
63
|
+
| `scope` | `string` | Space-separated scopes. Defaults to `openid profile email`. |
|
|
64
|
+
| `storage` | `SupportedStorage` | Custom storage adapter. Defaults to `localStorage`. |
|
|
65
|
+
| `storageKey` | `string` | Prefix for the storage key. Final key is `${storageKey}-${clientId}`. |
|
|
66
|
+
| `cookieOptions` | `CookieOptions` | When set, switches storage to the cookie adapter. |
|
|
67
|
+
| `lock` | `LockFunc` | Custom locking primitive for concurrent refreshes. |
|
|
68
|
+
| `debug` | `boolean` | Enables verbose logging. |
|
|
69
|
+
|
|
70
|
+
## Authentication flows
|
|
71
|
+
|
|
72
|
+
### OAuth / social connection
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
// Use the default connection configured on the tenant
|
|
76
|
+
await auth.signInWithOauthConnection({})
|
|
77
|
+
|
|
78
|
+
// Or pick a specific provider (by name or connection_id)
|
|
79
|
+
await auth.signInWithOauthConnection({
|
|
80
|
+
connection_id: 'conn_01HX…', // preferred when known; falls back to `connection` for legacy tenants
|
|
81
|
+
redirectTo: 'https://app.example.com/callback',
|
|
82
|
+
scopes: 'openid profile email',
|
|
83
|
+
queryParams: { prompt: 'select_account' }
|
|
84
|
+
})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
In browsers the SDK uses the PKCE flow by default and exchanges the `code` for a
|
|
88
|
+
session on the callback page. The first call to `createClient` automatically
|
|
89
|
+
processes the URL when the user lands back on the redirect target.
|
|
90
|
+
|
|
91
|
+
### Username + password
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
await auth.signInWithUsernamePassword({
|
|
95
|
+
username: 'user@example.com',
|
|
96
|
+
password: '••••••••',
|
|
97
|
+
redirectTo: 'https://app.example.com/callback'
|
|
98
|
+
})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Passwordless (magic link or OTP)
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
// Step 1 — request a code or link
|
|
105
|
+
await auth.signInWithPasswordless({
|
|
106
|
+
email: 'user@example.com',
|
|
107
|
+
type: 'code' // or "link"
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
// Step 2 — complete the login with the OTP the user received
|
|
111
|
+
const { data, error } = await auth.signInWithOtp({
|
|
112
|
+
username: 'user@example.com',
|
|
113
|
+
otp: '123456'
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Password reset
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
await auth.changePassword({ email: 'user@example.com' })
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Sign out
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
await auth.signOut() // global — all sessions for this user
|
|
127
|
+
await auth.signOut({ scope: 'local' }) // only this device
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Sessions and state changes
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
// Get the current session (refreshes if needed)
|
|
134
|
+
const {
|
|
135
|
+
data: { session }
|
|
136
|
+
} = await auth.getSession()
|
|
137
|
+
|
|
138
|
+
// Subscribe to auth events
|
|
139
|
+
const {
|
|
140
|
+
data: { subscription }
|
|
141
|
+
} = auth.onAuthStateChange((event, session) => {
|
|
142
|
+
// event: INITIAL_SESSION | SIGNED_IN | SIGNED_OUT | TOKEN_REFRESHED | PASSWORD_RECOVERY | USER_UPDATED
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
// Stop listening
|
|
146
|
+
subscription.unsubscribe()
|
|
147
|
+
|
|
148
|
+
// Force a refresh
|
|
149
|
+
await auth.refreshSession()
|
|
25
150
|
```
|
|
26
151
|
|
|
27
|
-
|
|
152
|
+
Auth events are broadcast across tabs using `BroadcastChannel`, so a sign-in or
|
|
153
|
+
sign-out in one tab is reflected in every other tab using the same `storageKey`.
|
|
154
|
+
|
|
155
|
+
## Storage adapters
|
|
156
|
+
|
|
157
|
+
### Trade-offs
|
|
158
|
+
|
|
159
|
+
Refresh tokens are sensitive: anyone who reads them can impersonate the user
|
|
160
|
+
until the token is revoked. The storage you pick decides where they live:
|
|
161
|
+
|
|
162
|
+
- **`localStorage` (default)** — simple and supports cross-tab sync via
|
|
163
|
+
`BroadcastChannel`, but any script running on the same origin can read it. **A
|
|
164
|
+
single XSS lets an attacker exfiltrate the refresh token.** Acceptable for
|
|
165
|
+
low-risk apps and prototypes; not recommended when the surface has third-party
|
|
166
|
+
scripts, user-generated HTML, or strict compliance requirements.
|
|
167
|
+
- **Cookies** — required for SSR (server reads them on every request) and the
|
|
168
|
+
only adapter that lets you scope storage with `Secure`, `SameSite`, and
|
|
169
|
+
`Domain`. Note that this library writes cookies from JavaScript, so they
|
|
170
|
+
cannot be marked `HttpOnly`; an XSS can still read them, but cookies make CSRF
|
|
171
|
+
and same-site policies enforceable in a way `localStorage` does not.
|
|
172
|
+
- **Custom adapter** — use for in-memory storage (tokens lost on reload, safest
|
|
173
|
+
against XSS), Web Workers, or platform-specific keychains.
|
|
174
|
+
|
|
175
|
+
If your app is exposed to untrusted content, prefer cookies with `Secure: true`
|
|
176
|
+
and `SameSite: "Lax"` (or `"Strict"`), and treat XSS prevention (CSP, escaping,
|
|
177
|
+
framework guarantees) as a hard requirement regardless of which adapter you
|
|
178
|
+
pick.
|
|
179
|
+
|
|
180
|
+
### localStorage (default)
|
|
181
|
+
|
|
182
|
+
Used automatically in browsers. No configuration required.
|
|
28
183
|
|
|
29
|
-
|
|
30
|
-
|
|
184
|
+
### Cookies
|
|
185
|
+
|
|
186
|
+
Useful for SSR setups where the server must read the session from the request.
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
import { createClient } from '@faable/auth-js'
|
|
31
190
|
|
|
32
191
|
export const auth = createClient({
|
|
33
|
-
domain:
|
|
34
|
-
clientId:
|
|
35
|
-
|
|
192
|
+
domain: '<faableauth_domain>',
|
|
193
|
+
clientId: '<client_id>',
|
|
194
|
+
storage: 'cookie'
|
|
195
|
+
})
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
That's it. The adapter sets sensible defaults: `Path=/`, `SameSite=Lax`, auto
|
|
199
|
+
`Secure` on HTTPS, and a 30-day `Max-Age` so users stay signed in across browser
|
|
200
|
+
restarts.
|
|
201
|
+
|
|
202
|
+
Use `cookieOptions` only when you need to override something — e.g. share the
|
|
203
|
+
session across subdomains:
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
createClient({
|
|
207
|
+
domain: '<faableauth_domain>',
|
|
208
|
+
clientId: '<client_id>',
|
|
209
|
+
storage: 'cookie',
|
|
210
|
+
cookieOptions: { domain: '.example.com' }
|
|
211
|
+
})
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Custom adapter
|
|
215
|
+
|
|
216
|
+
Provide any object that implements `getItem`, `setItem`, and `removeItem` (sync
|
|
217
|
+
or async). Set `isServer: true` if values may come from an untrusted source such
|
|
218
|
+
as request cookies.
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
const memoryStorage = {
|
|
222
|
+
store: new Map<string, string>(),
|
|
223
|
+
getItem: (k: string) => memoryStorage.store.get(k) ?? null,
|
|
224
|
+
setItem: (k: string, v: string) => void memoryStorage.store.set(k, v),
|
|
225
|
+
removeItem: (k: string) => void memoryStorage.store.delete(k)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
createClient({ domain, clientId, storage: memoryStorage })
|
|
36
229
|
```
|
|
37
230
|
|
|
38
|
-
##
|
|
231
|
+
## Next.js / server-side
|
|
39
232
|
|
|
40
|
-
|
|
233
|
+
Use cookie storage on the client, then read the session from `next/headers` on
|
|
234
|
+
the server:
|
|
41
235
|
|
|
42
|
-
```
|
|
43
|
-
//
|
|
44
|
-
|
|
236
|
+
```ts
|
|
237
|
+
// app/page.tsx
|
|
238
|
+
import { cookies } from "next/headers";
|
|
239
|
+
import { getSessionFromCookies } from "@faable/auth-js";
|
|
45
240
|
|
|
46
|
-
|
|
47
|
-
auth.
|
|
48
|
-
|
|
49
|
-
}
|
|
241
|
+
export default async function Page() {
|
|
242
|
+
const session = getSessionFromCookies(cookies(), "faable.auth.token-<client_id>");
|
|
243
|
+
if (!session) return <SignIn />;
|
|
244
|
+
return <Dashboard user={session.user} />;
|
|
245
|
+
}
|
|
50
246
|
```
|
|
247
|
+
|
|
248
|
+
The storage key follows the pattern
|
|
249
|
+
`${storageKey ?? "faable.auth.token"}-${clientId}`.
|
|
250
|
+
|
|
251
|
+
## License
|
|
252
|
+
|
|
253
|
+
See [LICENSE.md](LICENSE.md).
|
package/dist/dts/Base.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseLog, BaseLogOptions } from
|
|
2
|
-
import { AuthError } from
|
|
1
|
+
import { BaseLog, BaseLogOptions } from './BaseLog';
|
|
2
|
+
import { AuthError } from './lib/errors';
|
|
3
3
|
export default class FaableAuthApi extends BaseLog {
|
|
4
4
|
base_url: string;
|
|
5
5
|
constructor(base_url: string, config: BaseLogOptions);
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { getSessionFromCookies } from
|
|
1
|
+
import { Base } from './Base';
|
|
2
|
+
import FaableAuthApi from './FaableAuthApi';
|
|
3
|
+
import { BroadcastSync } from './lib/broadcast_sync';
|
|
4
|
+
import { AuthError } from './lib/errors';
|
|
5
|
+
import { Deferred } from './lib/helpers';
|
|
6
|
+
import { getSessionFromCookies } from './lib/nextjs';
|
|
7
|
+
import { cookieStorageAdapter } from './lib/storage/cookie-storage';
|
|
8
|
+
import { AuthFlowType, CallRefreshTokenResult, InitializeResult, OAuthResponse, SignInWithOAuthConnection, Subscription, SupportedStorage } from './lib/types';
|
|
9
|
+
import { AuthChangeEvent, AuthResponse, FaableAuthClientConfig } from './lib/types';
|
|
10
|
+
import { Session, SignOut } from './lib/types';
|
|
11
|
+
import { Lock } from './lock/Lock';
|
|
7
12
|
export { cookieStorageAdapter, getSessionFromCookies };
|
|
8
|
-
import { AuthError } from "./lib/errors";
|
|
9
|
-
import FaableAuthApi from "./FaableAuthApi";
|
|
10
|
-
import { Base } from "./Base";
|
|
11
|
-
import { Lock } from "./lock/Lock";
|
|
12
13
|
export declare class FaableAuthClient extends Base {
|
|
13
14
|
domainUrl: string;
|
|
14
15
|
tokenIssuer: string;
|
|
15
|
-
|
|
16
|
+
redirectUri: string;
|
|
16
17
|
scope?: string;
|
|
17
18
|
sessionCheckExpiryDays: number;
|
|
18
19
|
protected initializePromise: Promise<InitializeResult> | null;
|
|
@@ -26,11 +27,16 @@ export declare class FaableAuthClient extends Base {
|
|
|
26
27
|
protected visibilityChangedCallback: (() => Promise<any>) | null;
|
|
27
28
|
protected refreshingDeferred: Deferred<CallRefreshTokenResult> | null;
|
|
28
29
|
/**
|
|
29
|
-
*
|
|
30
|
+
* Cross-tab broadcaster + local subscriber registry for state changes.
|
|
30
31
|
*/
|
|
31
|
-
protected
|
|
32
|
-
protected stateChangeEmitters: Map<string, Subscription>;
|
|
32
|
+
protected broadcastSync: BroadcastSync;
|
|
33
33
|
protected _session: Session | null;
|
|
34
|
+
/**
|
|
35
|
+
* Initiation flow to use when redirecting to /authorize. Defaults to
|
|
36
|
+
* PKCE in browsers (recommended for SPAs) and implicit otherwise.
|
|
37
|
+
* Distinct from the callback-side flow which is detected from URL params.
|
|
38
|
+
*/
|
|
39
|
+
protected flowType: AuthFlowType;
|
|
34
40
|
protected lock: Lock;
|
|
35
41
|
constructor(config: FaableAuthClientConfig);
|
|
36
42
|
/**
|
|
@@ -83,8 +89,8 @@ export declare class FaableAuthClient extends Base {
|
|
|
83
89
|
* refresh the session. If refreshing fails it will be retried for as long as
|
|
84
90
|
* necessary.
|
|
85
91
|
*
|
|
86
|
-
* If
|
|
87
|
-
*
|
|
92
|
+
* If `autoRefreshToken` is enabled in the client config you don't need to
|
|
93
|
+
* call this function, it will be called for you.
|
|
88
94
|
*
|
|
89
95
|
* On browsers the refresh process works only when the tab/window is in the
|
|
90
96
|
* foreground to conserve resources as well as prevent race conditions and
|
|
@@ -121,9 +127,12 @@ export declare class FaableAuthClient extends Base {
|
|
|
121
127
|
signInWithUsernamePassword(data: {
|
|
122
128
|
username: string;
|
|
123
129
|
password: string;
|
|
124
|
-
|
|
130
|
+
redirectTo?: string;
|
|
125
131
|
state?: string;
|
|
126
|
-
}): Promise<
|
|
132
|
+
}): Promise<{
|
|
133
|
+
data: null;
|
|
134
|
+
error: AuthError | null;
|
|
135
|
+
}>;
|
|
127
136
|
/**
|
|
128
137
|
* Completes a passwordless login using an OTP code.
|
|
129
138
|
* @param data The username and OTP code.
|
|
@@ -138,14 +147,17 @@ export declare class FaableAuthClient extends Base {
|
|
|
138
147
|
*/
|
|
139
148
|
signInWithPasswordless(data: {
|
|
140
149
|
email: string;
|
|
141
|
-
type:
|
|
150
|
+
type: 'code' | 'link';
|
|
142
151
|
}): Promise<{
|
|
143
152
|
data: any;
|
|
144
153
|
error: AuthError | null;
|
|
145
154
|
}>;
|
|
146
155
|
changePassword(params: {
|
|
147
156
|
email: string;
|
|
148
|
-
}): Promise<
|
|
157
|
+
}): Promise<{
|
|
158
|
+
data: unknown;
|
|
159
|
+
error: AuthError | null;
|
|
160
|
+
}>;
|
|
149
161
|
buildAuthorizeUrl(options?: {
|
|
150
162
|
connection?: string;
|
|
151
163
|
redirectTo?: string;
|
|
@@ -210,7 +222,6 @@ export declare class FaableAuthClient extends Base {
|
|
|
210
222
|
*/
|
|
211
223
|
private __loadSession;
|
|
212
224
|
private _removeSession;
|
|
213
|
-
private _isValidSession;
|
|
214
225
|
protected _setSession(currentSession: {
|
|
215
226
|
access_token: string;
|
|
216
227
|
refresh_token: string;
|
|
@@ -239,9 +250,7 @@ export declare class FaableAuthClient extends Base {
|
|
|
239
250
|
signOut(options?: SignOut): Promise<{
|
|
240
251
|
error: AuthError | null;
|
|
241
252
|
}>;
|
|
242
|
-
protected _signOut({ scope
|
|
243
|
-
returnTo?: string;
|
|
244
|
-
}): Promise<{
|
|
253
|
+
protected _signOut({ scope }?: SignOut): Promise<{
|
|
245
254
|
error: AuthError | null;
|
|
246
255
|
}>;
|
|
247
256
|
/**
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { FaableAuthClient } from
|
|
2
|
-
import { FaableAuthClientConfig } from
|
|
1
|
+
import { FaableAuthClient } from './FaableAuthClient';
|
|
2
|
+
import { FaableAuthClientConfig } from './lib/types';
|
|
3
3
|
export declare const createClient: (config: FaableAuthClientConfig) => FaableAuthClient;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { FaableAuthClient, cookieStorageAdapter, getSessionFromCookies } from './FaableAuthClient';
|
|
2
|
+
import { createClient } from './createClient';
|
|
3
|
+
import { AuthError } from './lib/errors';
|
|
4
|
+
import { Session, User } from './lib/types';
|
|
5
|
+
import type { AuthChangeEvent, AuthFlowType, AuthResponse, CookieOptions, FaableAuthClientConfig, OAuthResponse, Provider, SignInWithOAuthConnection, SignOut, Subscription, SupportedStorage } from './lib/types';
|
|
6
|
+
export { Session, User, FaableAuthClient, AuthError, createClient, cookieStorageAdapter, getSessionFromCookies };
|
|
7
|
+
export type { FaableAuthClientConfig, SignInWithOAuthConnection, AuthResponse, AuthChangeEvent, Subscription, SignOut, SupportedStorage, CookieOptions, OAuthResponse, AuthFlowType, Provider };
|
|
@@ -1,5 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { Session, User } from "../lib/types";
|
|
3
|
-
import { AuthError } from "../lib/errors";
|
|
4
|
-
import { createClient } from "../createClient";
|
|
5
|
-
export { Session, User, FaableAuthClient, AuthError, createClient };
|
|
1
|
+
export * from '../entry';
|
|
@@ -1,5 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { Session, User } from "../lib/types";
|
|
3
|
-
import { AuthError } from "../lib/errors";
|
|
4
|
-
import { createClient } from "../createClient";
|
|
5
|
-
export { Session, User, FaableAuthClient, AuthError, createClient };
|
|
1
|
+
export * from '../entry';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Picks the OAuth `response_type` for an authorize request.
|
|
3
|
+
*
|
|
4
|
+
* Browsers default to the authorization code flow (PKCE); non-browser
|
|
5
|
+
* environments default to the implicit token flow. A caller-provided
|
|
6
|
+
* value always wins.
|
|
7
|
+
*/
|
|
8
|
+
export declare const resolveResponseType: (options: {
|
|
9
|
+
response_type?: string;
|
|
10
|
+
}, isBrowserEnv: boolean) => string;
|
|
11
|
+
/**
|
|
12
|
+
* Renders an HTML form returned by the authorization server and submits it,
|
|
13
|
+
* triggering the browser navigation that completes the username/password
|
|
14
|
+
* login flow.
|
|
15
|
+
*/
|
|
16
|
+
export declare const buildAndSubmitForm: (formHtml: string, doc: Document) => void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AuthChangeEvent, Session, Subscription } from './types';
|
|
2
|
+
type Listener = (event: AuthChangeEvent, session: Session | null) => void | Promise<void>;
|
|
3
|
+
type DebugFn = (message: string, ...args: unknown[]) => void;
|
|
4
|
+
/**
|
|
5
|
+
* Wraps a BroadcastChannel plus an in-process subscriber registry so the
|
|
6
|
+
* auth client can fan out state changes to local subscribers and other tabs
|
|
7
|
+
* in one call. Cross-tab messages are delivered to local subscribers but
|
|
8
|
+
* NOT re-broadcast, to avoid echo loops.
|
|
9
|
+
*/
|
|
10
|
+
export declare class BroadcastSync {
|
|
11
|
+
private debug;
|
|
12
|
+
private channel;
|
|
13
|
+
private subscribers;
|
|
14
|
+
constructor(channelName: string, debug: DebugFn);
|
|
15
|
+
subscribe(callback: Listener): {
|
|
16
|
+
subscription: Subscription;
|
|
17
|
+
};
|
|
18
|
+
notify(event: AuthChangeEvent, session: Session | null, broadcast?: boolean): Promise<void>;
|
|
19
|
+
private dispatch;
|
|
20
|
+
close(): void;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
export declare const GOTRUE_URL = "http://localhost:9999";
|
|
2
1
|
export declare const STORAGE_KEY = "faableauth";
|
|
3
2
|
export declare const EXPIRY_MARGIN = 10;
|
|
4
3
|
export declare const API_VERSION_HEADER_NAME = "X-Faableauth-Api-Version";
|
|
5
4
|
export declare const API_VERSIONS: {
|
|
6
|
-
|
|
5
|
+
'2024-01-01': {
|
|
7
6
|
timestamp: number;
|
|
8
7
|
name: string;
|
|
9
8
|
};
|
package/dist/dts/lib/errors.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* not included in this list (if the client library is older than the version
|
|
4
4
|
* on the server).
|
|
5
5
|
*/
|
|
6
|
-
export type ErrorCode =
|
|
6
|
+
export type ErrorCode = 'unexpected_failure' | 'validation_failed' | 'bad_json' | 'email_exists' | 'phone_exists' | 'bad_jwt' | 'not_admin' | 'no_authorization' | 'user_not_found' | 'session_not_found' | 'flow_state_not_found' | 'flow_state_expired' | 'signup_disabled' | 'user_banned' | 'provider_email_needs_verification' | 'invite_not_found' | 'bad_oauth_state' | 'bad_oauth_callback' | 'oauth_provider_not_supported' | 'unexpected_audience' | 'single_identity_not_deletable' | 'email_conflict_identity_not_deletable' | 'identity_already_exists' | 'email_provider_disabled' | 'phone_provider_disabled' | 'too_many_enrolled_mfa_factors' | 'mfa_factor_name_conflict' | 'mfa_factor_not_found' | 'mfa_ip_address_mismatch' | 'mfa_challenge_expired' | 'mfa_verification_failed' | 'mfa_verification_rejected' | 'insufficient_aal' | 'captcha_failed' | 'saml_provider_disabled' | 'manual_linking_disabled' | 'sms_send_failed' | 'email_not_confirmed' | 'phone_not_confirmed' | 'reauth_nonce_missing' | 'saml_relay_state_not_found' | 'saml_relay_state_expired' | 'saml_idp_not_found' | 'saml_assertion_no_user_id' | 'saml_assertion_no_email' | 'user_already_exists' | 'sso_provider_not_found' | 'saml_metadata_fetch_failed' | 'saml_idp_already_exists' | 'sso_domain_already_exists' | 'saml_entity_id_mismatch' | 'conflict' | 'provider_disabled' | 'user_sso_managed' | 'reauthentication_needed' | 'same_password' | 'reauthentication_not_valid' | 'otp_expired' | 'otp_disabled' | 'identity_not_found' | 'weak_password' | 'over_request_rate_limit' | 'over_email_send_rate_limit' | 'over_sms_send_rate_limit' | 'bad_code_verifier';
|
|
7
7
|
export declare class AuthError extends Error {
|
|
8
8
|
/**
|
|
9
9
|
* Error code associated with the error. Most errors coming from
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { JsonResponse } from './fetch';
|
|
2
|
+
import { AuthResponse, SupportedStorage, User } from './types';
|
|
3
3
|
export declare function decodeBase64URL(value: string): string;
|
|
4
4
|
export declare function generatePKCEVerifier(): string;
|
|
5
5
|
export declare function generatePKCEChallenge(verifier: string): Promise<string>;
|
|
@@ -19,7 +19,7 @@ export type RawAuthResponse = {
|
|
|
19
19
|
token_type: string;
|
|
20
20
|
};
|
|
21
21
|
export declare function expiresAt(expiresIn: number): number;
|
|
22
|
-
export declare function _sessionResponse({ data
|
|
22
|
+
export declare function _sessionResponse({ data }: JsonResponse<Partial<RawAuthResponse>>): AuthResponse;
|
|
23
23
|
/**
|
|
24
24
|
* A deferred represents some asynchronous work that is not yet finished, which
|
|
25
25
|
* may or may not culminate in a value.
|
|
@@ -42,7 +42,7 @@ export declare function retryable<T>(fn: (attempt: number) => Promise<T>, isRetr
|
|
|
42
42
|
* Creates a promise that resolves to null after some time.
|
|
43
43
|
*/
|
|
44
44
|
export declare function sleep(time: number): Promise<null>;
|
|
45
|
-
export declare const checkExpiresInTime: ({ expires_in, expires_at, refreshTick
|
|
45
|
+
export declare const checkExpiresInTime: ({ expires_in, expires_at, refreshTick }: {
|
|
46
46
|
expires_in: string;
|
|
47
47
|
expires_at?: string;
|
|
48
48
|
refreshTick: number;
|
package/dist/dts/lib/nextjs.d.ts
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SupportedStorage } from './types';
|
|
2
|
+
export declare const CODE_VERIFIER_TTL_MS: number;
|
|
3
|
+
type LoadedCodeVerifier = {
|
|
4
|
+
verifier: string;
|
|
5
|
+
redirectType?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const saveCodeVerifier: (storage: SupportedStorage, key: string, { verifier, redirectType, now }: {
|
|
8
|
+
verifier: string;
|
|
9
|
+
redirectType?: string;
|
|
10
|
+
now?: number;
|
|
11
|
+
}) => Promise<void>;
|
|
12
|
+
export declare const loadCodeVerifier: (storage: SupportedStorage, key: string, { now }?: {
|
|
13
|
+
now?: number;
|
|
14
|
+
}) => Promise<LoadedCodeVerifier | null>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Session } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Type guard for a stored session blob — checks the presence of the fields
|
|
4
|
+
* the client needs to consider the value usable. Does not validate the
|
|
5
|
+
* cryptographic signature of the access/refresh tokens.
|
|
6
|
+
*/
|
|
7
|
+
export declare const isValidSession: (value: unknown) => value is Session;
|
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import { SupportedStorage } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { SupportedStorage } from '../types';
|
|
2
|
+
import { CookieAttributes } from './cookie_helpers';
|
|
3
|
+
export type CookieOptions = CookieAttributes;
|
|
4
|
+
/**
|
|
5
|
+
* Document-like surface the cookie adapter needs. Accepting a minimal shape
|
|
6
|
+
* (instead of the full DOM `Document`) keeps the adapter testable without
|
|
7
|
+
* jsdom and works in any environment that exposes a `cookie` property.
|
|
8
|
+
*/
|
|
9
|
+
export interface CookieJar {
|
|
10
|
+
cookie: string;
|
|
8
11
|
}
|
|
9
12
|
/**
|
|
10
|
-
* A storage adapter that uses document.cookie to persist
|
|
11
|
-
*
|
|
13
|
+
* A storage adapter that uses `document.cookie` to persist sessions. Useful
|
|
14
|
+
* in SSR setups where the server reads the cookie on every request.
|
|
15
|
+
*
|
|
16
|
+
* The optional `jar` parameter lets tests inject a fake document; production
|
|
17
|
+
* code passes nothing and the adapter uses the real `document` in browsers
|
|
18
|
+
* (and no-ops on the server).
|
|
12
19
|
*/
|
|
13
|
-
export declare const cookieStorageAdapter: (options?: CookieOptions) => SupportedStorage;
|
|
14
|
-
export {};
|
|
20
|
+
export declare const cookieStorageAdapter: (options?: CookieOptions, jar?: CookieJar | null) => SupportedStorage;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface CookieAttributes {
|
|
2
|
+
domain?: string;
|
|
3
|
+
path?: string;
|
|
4
|
+
sameSite?: 'Lax' | 'Strict' | 'None';
|
|
5
|
+
secure?: boolean;
|
|
6
|
+
maxAge?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Parses a raw cookie string (the shape of `document.cookie`) into a Map of
|
|
10
|
+
* decoded name → value. Splitting happens BEFORE decoding so encoded `;` and
|
|
11
|
+
* `=` characters inside a value don't break the parser.
|
|
12
|
+
*/
|
|
13
|
+
export declare const parseCookies: (cookieString: string) => Map<string, string>;
|
|
14
|
+
/**
|
|
15
|
+
* Builds a `name=value; Attr=...` string suitable for assignment to
|
|
16
|
+
* `document.cookie`. Encodes name and value per RFC 6265 and forces `Secure`
|
|
17
|
+
* when `SameSite=None` (browsers reject the cookie otherwise).
|
|
18
|
+
*/
|
|
19
|
+
export declare const serializeCookie: (name: string, value: string, attrs: CookieAttributes) => string;
|
|
20
|
+
/**
|
|
21
|
+
* Builds the cookie string that clears `name`. Browsers will only remove a
|
|
22
|
+
* cookie when the deletion attributes (Domain, Path, SameSite, Secure) match
|
|
23
|
+
* those used at write time, so we mirror them here.
|
|
24
|
+
*/
|
|
25
|
+
export declare const serializeCookieRemoval: (name: string, attrs: CookieAttributes) => string;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { SupportedStorage } from
|
|
1
|
+
import { SupportedStorage } from './types';
|
|
2
2
|
export declare const setItemAsync: (storage: SupportedStorage, key: string, data: any) => Promise<void>;
|
|
3
3
|
export declare const getItemAsync: (storage: SupportedStorage, key: string) => Promise<unknown>;
|