@authgate/browser 0.3.0 → 0.4.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 +41 -8
- package/dist/index.d.ts +31 -12
- package/dist/index.js +32 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ framework-specific abstractions.
|
|
|
24
24
|
|
|
25
25
|
- Read AuthGate CSRF token from browser cookies
|
|
26
26
|
- Perform a CSRF-protected logout request
|
|
27
|
-
- Explicit browser-side session refresh
|
|
27
|
+
- Explicit browser-side session refresh **with audience selection**
|
|
28
28
|
- Optional `fetch` wrapper with **single-retry refresh semantics**
|
|
29
29
|
- Clear success / failure signaling
|
|
30
30
|
- Optional redirect on logout
|
|
@@ -57,7 +57,7 @@ It does not generate or validate it.
|
|
|
57
57
|
|
|
58
58
|
---
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
## Logout
|
|
61
61
|
|
|
62
62
|
```ts
|
|
63
63
|
import { logout } from "@authgate/browser";
|
|
@@ -103,16 +103,28 @@ Redirecting is an optional side-effect and does **not** define success.
|
|
|
103
103
|
```ts
|
|
104
104
|
import { refreshSession } from "@authgate/browser";
|
|
105
105
|
|
|
106
|
-
const refreshed = await refreshSession();
|
|
106
|
+
const refreshed = await refreshSession("app");
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
Attempts to refresh the current AuthGate session by calling:
|
|
110
110
|
|
|
111
|
-
```
|
|
111
|
+
```text
|
|
112
112
|
POST /auth/refresh
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
with an explicit **audience declaration**.
|
|
116
|
+
|
|
117
|
+
### Audience
|
|
118
|
+
|
|
119
|
+
The audience determines **which access token is minted** (e.g. `"app"`, `"admin"`).
|
|
120
|
+
|
|
121
|
+
- The client explicitly requests an audience
|
|
122
|
+
- AuthGate validates the requested audience against the user’s roles
|
|
123
|
+
- Requests for unauthorized audiences fail with `401`
|
|
124
|
+
|
|
125
|
+
If no audience is provided, `"app"` is used by default.
|
|
126
|
+
|
|
127
|
+
### Behavior
|
|
116
128
|
|
|
117
129
|
- Returns `true` if refresh succeeded
|
|
118
130
|
- Returns `false` if refresh failed for any reason
|
|
@@ -141,16 +153,25 @@ const res = await authFetch("/api/data");
|
|
|
141
153
|
`authFetch` is an **optional convenience wrapper** around `fetch` with
|
|
142
154
|
AuthGate-aware refresh behavior.
|
|
143
155
|
|
|
144
|
-
Behavior
|
|
156
|
+
### Behavior
|
|
145
157
|
|
|
146
158
|
1. Performs the request with credentials
|
|
147
159
|
2. If the response is **not `401`**, returns it directly
|
|
148
160
|
3. If the response **is `401`**:
|
|
149
|
-
- Attempts `refreshSession()`
|
|
161
|
+
- Attempts `refreshSession()` with the same audience
|
|
150
162
|
- If refresh succeeds, retries the original request **once**
|
|
151
163
|
- Otherwise, returns the original `401` response
|
|
152
164
|
|
|
153
|
-
|
|
165
|
+
### Audience-aware requests
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
await authFetch("/admin/api/users", {}, { audience: "admin" });
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
- The same audience is used for the refresh attempt
|
|
172
|
+
- Unauthorized audiences fail cleanly without retry loops
|
|
173
|
+
|
|
174
|
+
### Important properties
|
|
154
175
|
|
|
155
176
|
- At most **one retry**
|
|
156
177
|
- No redirects
|
|
@@ -171,6 +192,16 @@ if (res.status === 401) {
|
|
|
171
192
|
}
|
|
172
193
|
```
|
|
173
194
|
|
|
195
|
+
Admin request:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
const res = await authFetch(
|
|
199
|
+
"/admin/api/users",
|
|
200
|
+
{},
|
|
201
|
+
{ audience: "admin" },
|
|
202
|
+
);
|
|
203
|
+
```
|
|
204
|
+
|
|
174
205
|
---
|
|
175
206
|
|
|
176
207
|
## Security model
|
|
@@ -179,6 +210,7 @@ if (res.status === 401) {
|
|
|
179
210
|
- CSRF validation is **enforced by AuthGate**
|
|
180
211
|
- Refresh tokens are **never exposed to JavaScript**
|
|
181
212
|
- All authentication state is owned by AuthGate
|
|
213
|
+
- Audiences are **explicitly requested and server-validated**
|
|
182
214
|
|
|
183
215
|
This package only forwards existing browser state explicitly.
|
|
184
216
|
|
|
@@ -202,6 +234,7 @@ while preserving full application control.
|
|
|
202
234
|
## Compatibility
|
|
203
235
|
|
|
204
236
|
- Works with any backend protected by AuthGate
|
|
237
|
+
- Supports SSR, SPA, and hybrid architectures
|
|
205
238
|
|
|
206
239
|
---
|
|
207
240
|
|
package/dist/index.d.ts
CHANGED
|
@@ -38,27 +38,46 @@ export declare function logout(opts?: {
|
|
|
38
38
|
redirectTo?: string;
|
|
39
39
|
}): Promise<LogoutResult>;
|
|
40
40
|
/**
|
|
41
|
-
* authFetch performs a fetch request with AuthGate-aware refresh-once behavior
|
|
41
|
+
* authFetch performs a fetch request with AuthGate-aware, refresh-once behavior
|
|
42
|
+
* for a specific audience.
|
|
42
43
|
*
|
|
43
44
|
* Behavior:
|
|
44
45
|
* - Always includes credentials
|
|
45
|
-
* -
|
|
46
|
+
* - Performs the initial request as-is
|
|
47
|
+
* - If the response is NOT 401, returns it directly
|
|
46
48
|
* - If the response IS 401:
|
|
47
|
-
* - Attempts POST /auth/refresh with CSRF
|
|
48
|
-
* - If refresh succeeds
|
|
49
|
-
* -
|
|
49
|
+
* - Attempts POST /auth/refresh with CSRF and the same requested audience
|
|
50
|
+
* - If refresh succeeds, retries the original request ONCE
|
|
51
|
+
* - If refresh fails, returns the original 401 response
|
|
52
|
+
*
|
|
53
|
+
* authFetch never redirects or mutates application state. Callers are expected
|
|
54
|
+
* to handle authentication failures explicitly.
|
|
55
|
+
*
|
|
56
|
+
* @param input The resource to fetch (same as `fetch`).
|
|
57
|
+
* @param init Optional fetch options. Credentials are always included.
|
|
58
|
+
* @param opts Optional AuthGate options.
|
|
59
|
+
* @param opts.audience The audience for which the request is made (e.g. "app", "admin").
|
|
60
|
+
* Defaults to "app".
|
|
61
|
+
* @returns The final `Response` from the original request or the retried request.
|
|
50
62
|
*/
|
|
51
|
-
export declare function authFetch(input: RequestInfo | URL, init?: RequestInit
|
|
63
|
+
export declare function authFetch(input: RequestInfo | URL, init?: RequestInit, opts?: {
|
|
64
|
+
audience?: string;
|
|
65
|
+
}): Promise<Response>;
|
|
52
66
|
/**
|
|
53
|
-
* refreshSession attempts to refresh the current AuthGate session
|
|
67
|
+
* refreshSession attempts to refresh the current AuthGate session for a
|
|
68
|
+
* specific audience.
|
|
54
69
|
*
|
|
55
70
|
* It performs:
|
|
56
71
|
* POST /auth/refresh
|
|
57
|
-
* with CSRF protection and
|
|
72
|
+
* with CSRF protection, credentials, and an explicit audience declaration.
|
|
73
|
+
*
|
|
74
|
+
* The server validates the requested audience against the user's roles and
|
|
75
|
+
* rejects the request if the audience is not permitted.
|
|
58
76
|
*
|
|
59
|
-
* The
|
|
60
|
-
*
|
|
61
|
-
*
|
|
77
|
+
* @param audience The audience for which a new access token should be minted.
|
|
78
|
+
* Defaults to "app".
|
|
79
|
+
* @returns `true` if the refresh succeeded, or `false` if refresh failed for
|
|
80
|
+
* any reason (unauthorized, expired session, or error).
|
|
62
81
|
*/
|
|
63
|
-
export declare function refreshSession(): Promise<boolean>;
|
|
82
|
+
export declare function refreshSession(audience?: string): Promise<boolean>;
|
|
64
83
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -68,22 +68,35 @@ export async function logout(opts) {
|
|
|
68
68
|
return { ok: true };
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
71
|
-
* authFetch performs a fetch request with AuthGate-aware refresh-once behavior
|
|
71
|
+
* authFetch performs a fetch request with AuthGate-aware, refresh-once behavior
|
|
72
|
+
* for a specific audience.
|
|
72
73
|
*
|
|
73
74
|
* Behavior:
|
|
74
75
|
* - Always includes credentials
|
|
75
|
-
* -
|
|
76
|
+
* - Performs the initial request as-is
|
|
77
|
+
* - If the response is NOT 401, returns it directly
|
|
76
78
|
* - If the response IS 401:
|
|
77
|
-
* - Attempts POST /auth/refresh with CSRF
|
|
78
|
-
* - If refresh succeeds
|
|
79
|
-
* -
|
|
79
|
+
* - Attempts POST /auth/refresh with CSRF and the same requested audience
|
|
80
|
+
* - If refresh succeeds, retries the original request ONCE
|
|
81
|
+
* - If refresh fails, returns the original 401 response
|
|
82
|
+
*
|
|
83
|
+
* authFetch never redirects or mutates application state. Callers are expected
|
|
84
|
+
* to handle authentication failures explicitly.
|
|
85
|
+
*
|
|
86
|
+
* @param input The resource to fetch (same as `fetch`).
|
|
87
|
+
* @param init Optional fetch options. Credentials are always included.
|
|
88
|
+
* @param opts Optional AuthGate options.
|
|
89
|
+
* @param opts.audience The audience for which the request is made (e.g. "app", "admin").
|
|
90
|
+
* Defaults to "app".
|
|
91
|
+
* @returns The final `Response` from the original request or the retried request.
|
|
80
92
|
*/
|
|
81
|
-
export async function authFetch(input, init = {}) {
|
|
93
|
+
export async function authFetch(input, init = {}, opts) {
|
|
94
|
+
const audience = opts?.audience ?? "app";
|
|
82
95
|
const res = await fetch(input, withCredentials(init));
|
|
83
96
|
if (res.status !== 401) {
|
|
84
97
|
return res;
|
|
85
98
|
}
|
|
86
|
-
const refreshed = await refreshSession();
|
|
99
|
+
const refreshed = await refreshSession(audience);
|
|
87
100
|
if (!refreshed) {
|
|
88
101
|
return res;
|
|
89
102
|
}
|
|
@@ -96,24 +109,29 @@ function withCredentials(init) {
|
|
|
96
109
|
};
|
|
97
110
|
}
|
|
98
111
|
/**
|
|
99
|
-
* refreshSession attempts to refresh the current AuthGate session
|
|
112
|
+
* refreshSession attempts to refresh the current AuthGate session for a
|
|
113
|
+
* specific audience.
|
|
100
114
|
*
|
|
101
115
|
* It performs:
|
|
102
116
|
* POST /auth/refresh
|
|
103
|
-
* with CSRF protection and
|
|
117
|
+
* with CSRF protection, credentials, and an explicit audience declaration.
|
|
118
|
+
*
|
|
119
|
+
* The server validates the requested audience against the user's roles and
|
|
120
|
+
* rejects the request if the audience is not permitted.
|
|
104
121
|
*
|
|
105
|
-
* The
|
|
106
|
-
*
|
|
107
|
-
*
|
|
122
|
+
* @param audience The audience for which a new access token should be minted.
|
|
123
|
+
* Defaults to "app".
|
|
124
|
+
* @returns `true` if the refresh succeeded, or `false` if refresh failed for
|
|
125
|
+
* any reason (unauthorized, expired session, or error).
|
|
108
126
|
*/
|
|
109
|
-
export async function refreshSession() {
|
|
127
|
+
export async function refreshSession(audience = "app") {
|
|
110
128
|
const csrf = getCSRFToken();
|
|
111
129
|
if (!csrf) {
|
|
112
130
|
return false;
|
|
113
131
|
}
|
|
114
132
|
let res;
|
|
115
133
|
try {
|
|
116
|
-
res = await fetch(
|
|
134
|
+
res = await fetch(`/auth/refresh?audience=${encodeURIComponent(audience)}`, {
|
|
117
135
|
method: "POST",
|
|
118
136
|
headers: {
|
|
119
137
|
"X-CSRF-Token": csrf,
|
package/package.json
CHANGED