@authgate/browser 0.2.0 → 0.3.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 CHANGED
@@ -2,20 +2,33 @@
2
2
 
3
3
  Minimal browser-side helpers for applications using **AuthGate**.
4
4
 
5
- This package provides small, explicit utilities to integrate browser-based UIs
6
- with an AuthGate-backed authentication flow. It intentionally avoids framework
7
- coupling and hidden behavior.
5
+ This package provides **explicit, framework-agnostic primitives** for integrating
6
+ browser-based UIs (SSR or SPA) with an AuthGate-backed authentication system.
7
+
8
+ It intentionally avoids hidden behavior, background state mutation, or
9
+ framework-specific abstractions.
8
10
 
9
11
  ---
10
12
 
11
- ## Features
13
+ ## Design goals
12
14
 
13
- - Read AuthGate CSRF token from cookies
14
- - Perform a safe logout request with CSRF protection
15
- - Explicit success/failure signaling
16
- - Optional redirect after logout
15
+ - Explicit behavior (no magic, no background auth)
16
+ - Browser-only responsibility (cookies, CSRF, refresh)
17
+ - Framework-agnostic (React, Vue, Svelte, vanilla JS)
18
+ - Composable primitives + optional convenience helpers
17
19
  - Zero dependencies
18
- - Framework-agnostic (works with React, Vue, vanilla JS, etc.)
20
+
21
+ ---
22
+
23
+ ## Features
24
+
25
+ - Read AuthGate CSRF token from browser cookies
26
+ - Perform a CSRF-protected logout request
27
+ - Explicit browser-side session refresh
28
+ - Optional `fetch` wrapper with **single-retry refresh semantics**
29
+ - Clear success / failure signaling
30
+ - Optional redirect on logout
31
+ - No runtime dependencies
19
32
 
20
33
  ---
21
34
 
@@ -39,7 +52,8 @@ const csrf = getCSRFToken();
39
52
 
40
53
  Returns the value of the `authgate_csrf` cookie, or `null` if not present.
41
54
 
42
- This function only **reads** the CSRF token. It does not generate or validate it.
55
+ This function only **reads** the CSRF token.
56
+ It does not generate or validate it.
43
57
 
44
58
  ---
45
59
 
@@ -57,7 +71,7 @@ This will:
57
71
  - Attach the CSRF token via `X-CSRF-Token`
58
72
  - Include credentials (`cookies`)
59
73
 
60
- The function returns a result indicating whether logout succeeded:
74
+ The function returns an explicit result:
61
75
 
62
76
  ```ts
63
77
  type LogoutResult =
@@ -65,8 +79,8 @@ type LogoutResult =
65
79
  | { ok: false; reason: "missing_csrf" | "request_failed" | "unauthorized" };
66
80
  ```
67
81
 
68
- Applications that do not need to react programmatically to logout may safely
69
- ignore the return value.
82
+ Applications that do not need to react programmatically may safely ignore the
83
+ return value.
70
84
 
71
85
  ---
72
86
 
@@ -79,54 +93,116 @@ await logout({ redirectTo: "/" });
79
93
  If the logout request succeeds, the browser is redirected to the given path.
80
94
 
81
95
  Redirecting is an optional side-effect and does **not** define success.
82
- Applications may choose to handle navigation themselves instead.
83
96
 
84
97
  ---
85
98
 
86
- ### Example (React / SPA)
99
+ ## Session refresh (explicit)
100
+
101
+ ### `refreshSession`
87
102
 
88
103
  ```ts
89
- const result = await logout();
104
+ import { refreshSession } from "@authgate/browser";
105
+
106
+ const refreshed = await refreshSession();
107
+ ```
90
108
 
91
- if (result.ok) {
109
+ Attempts to refresh the current AuthGate session by calling:
110
+
111
+ ```
112
+ POST /auth/refresh
113
+ ```
114
+
115
+ Behavior:
116
+
117
+ - Returns `true` if refresh succeeded
118
+ - Returns `false` if refresh failed for any reason
119
+
120
+ This function:
121
+
122
+ - does **not** retry
123
+ - does **not** redirect
124
+ - does **not** throw
125
+ - does **not** modify application state
126
+
127
+ It is intended for applications that want **manual control** over refresh logic.
128
+
129
+ ---
130
+
131
+ ## Fetch wrapper (optional convenience)
132
+
133
+ ### `authFetch`
134
+
135
+ ```ts
136
+ import { authFetch } from "@authgate/browser";
137
+
138
+ const res = await authFetch("/api/data");
139
+ ```
140
+
141
+ `authFetch` is an **optional convenience wrapper** around `fetch` with
142
+ AuthGate-aware refresh behavior.
143
+
144
+ Behavior:
145
+
146
+ 1. Performs the request with credentials
147
+ 2. If the response is **not `401`**, returns it directly
148
+ 3. If the response **is `401`**:
149
+ - Attempts `refreshSession()`
150
+ - If refresh succeeds, retries the original request **once**
151
+ - Otherwise, returns the original `401` response
152
+
153
+ Important properties:
154
+
155
+ - At most **one retry**
156
+ - No redirects
157
+ - No background refresh
158
+ - No swallowed failures
159
+
160
+ Applications remain fully in control of UX decisions.
161
+
162
+ ---
163
+
164
+ ## Example (React / SPA)
165
+
166
+ ```ts
167
+ const res = await authFetch("/api/me");
168
+
169
+ if (res.status === 401) {
92
170
  setUser(null);
93
- } else {
94
- console.error("Logout failed:", result.reason);
95
171
  }
96
172
  ```
97
173
 
98
174
  ---
99
175
 
100
- ## Security Model
176
+ ## Security model
101
177
 
102
178
  - CSRF tokens are **not generated** by this package
103
179
  - CSRF validation is **enforced by AuthGate**
104
- - This package only forwards existing CSRF state
180
+ - Refresh tokens are **never exposed to JavaScript**
181
+ - All authentication state is owned by AuthGate
105
182
 
106
- No cookies are set, modified, or cleared by this library.
183
+ This package only forwards existing browser state explicitly.
107
184
 
108
185
  ---
109
186
 
110
- ## What This Package Does NOT Do
187
+ ## What this package does NOT do
111
188
 
112
189
  - No authentication logic
113
- - No token refresh
190
+ - No credential storage
191
+ - No background token refresh
114
192
  - No session management
193
+ - No authorization or role handling
115
194
  - No implicit redirects
116
195
  - No framework-specific helpers
117
196
 
118
- This package exists solely to reduce boilerplate and prevent integration mistakes.
197
+ This package exists solely to reduce boilerplate and prevent integration mistakes
198
+ while preserving full application control.
119
199
 
120
200
  ---
121
201
 
122
202
  ## Compatibility
123
203
 
124
204
  - Works with any backend protected by AuthGate
125
- - Compatible with SSR and SPA architectures
126
205
 
127
206
  ---
128
207
 
129
208
  ## License
130
-
131
- MIT
132
-
package/dist/index.d.ts CHANGED
@@ -37,4 +37,28 @@ type LogoutResult = {
37
37
  export declare function logout(opts?: {
38
38
  redirectTo?: string;
39
39
  }): Promise<LogoutResult>;
40
+ /**
41
+ * authFetch performs a fetch request with AuthGate-aware refresh-once behavior.
42
+ *
43
+ * Behavior:
44
+ * - Always includes credentials
45
+ * - If the response is NOT 401 - returns it directly
46
+ * - If the response IS 401:
47
+ * - Attempts POST /auth/refresh with CSRF
48
+ * - If refresh succeeds - retries original request ONCE
49
+ * - Otherwise - returns original 401 response
50
+ */
51
+ export declare function authFetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
52
+ /**
53
+ * refreshSession attempts to refresh the current AuthGate session.
54
+ *
55
+ * It performs:
56
+ * POST /auth/refresh
57
+ * with CSRF protection and credentials
58
+ *
59
+ * The function:
60
+ * - returns true if refresh succeeded
61
+ * - returns false if refresh failed for any reason
62
+ */
63
+ export declare function refreshSession(): Promise<boolean>;
40
64
  export {};
package/dist/index.js CHANGED
@@ -67,3 +67,62 @@ export async function logout(opts) {
67
67
  }
68
68
  return { ok: true };
69
69
  }
70
+ /**
71
+ * authFetch performs a fetch request with AuthGate-aware refresh-once behavior.
72
+ *
73
+ * Behavior:
74
+ * - Always includes credentials
75
+ * - If the response is NOT 401 - returns it directly
76
+ * - If the response IS 401:
77
+ * - Attempts POST /auth/refresh with CSRF
78
+ * - If refresh succeeds - retries original request ONCE
79
+ * - Otherwise - returns original 401 response
80
+ */
81
+ export async function authFetch(input, init = {}) {
82
+ const res = await fetch(input, withCredentials(init));
83
+ if (res.status !== 401) {
84
+ return res;
85
+ }
86
+ const refreshed = await refreshSession();
87
+ if (!refreshed) {
88
+ return res;
89
+ }
90
+ return fetch(input, withCredentials(init));
91
+ }
92
+ function withCredentials(init) {
93
+ return {
94
+ ...init,
95
+ credentials: "include",
96
+ };
97
+ }
98
+ /**
99
+ * refreshSession attempts to refresh the current AuthGate session.
100
+ *
101
+ * It performs:
102
+ * POST /auth/refresh
103
+ * with CSRF protection and credentials
104
+ *
105
+ * The function:
106
+ * - returns true if refresh succeeded
107
+ * - returns false if refresh failed for any reason
108
+ */
109
+ export async function refreshSession() {
110
+ const csrf = getCSRFToken();
111
+ if (!csrf) {
112
+ return false;
113
+ }
114
+ let res;
115
+ try {
116
+ res = await fetch("/auth/refresh", {
117
+ method: "POST",
118
+ headers: {
119
+ "X-CSRF-Token": csrf,
120
+ },
121
+ credentials: "include",
122
+ });
123
+ }
124
+ catch {
125
+ return false;
126
+ }
127
+ return res.ok;
128
+ }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "type": "git",
5
5
  "url": "https://github.com/alexlup06-authgate/authgate-browser.git"
6
6
  },
7
- "version": "0.2.0",
7
+ "version": "0.3.0",
8
8
  "description": "Browser-side helpers for AuthGate (logout, CSRF forwarding)",
9
9
  "license": "MIT",
10
10
  "type": "module",