@gosso/client 0.2.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/CHANGELOG.md +43 -0
- package/MIGRATING.md +15 -0
- package/README.md +29 -4
- package/SECURITY.md +6 -0
- package/dist/client.d.ts +76 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +800 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +46 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +71 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +6 -142
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -722
- package/dist/index.js.map +1 -1
- package/dist/pkce.d.ts +2 -0
- package/dist/pkce.d.ts.map +1 -0
- package/dist/pkce.js +13 -0
- package/dist/pkce.js.map +1 -0
- package/dist/types.d.ts +106 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +20 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +145 -0
- package/dist/utils.js.map +1 -0
- package/package.json +12 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,49 @@ The format is based on Keep a Changelog, and this project follows Semantic Versi
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.4.0] - 2026-08-24
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- Promote `0.4.0-rc.2` to `latest` without runtime code changes after Blog and Admin integration verification.
|
|
13
|
+
|
|
14
|
+
## [0.4.0-rc.2] - 2026-08-24
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- Correct the release workflow's tag-to-package version validation before its first npm publish attempt.
|
|
18
|
+
|
|
19
|
+
## [0.4.0-rc.1] - 2026-08-24
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- Add typed `ApiError` responses with HTTP status and stable error codes.
|
|
23
|
+
- Add SDK-owned password reset request and completion methods.
|
|
24
|
+
- Add exact `allowedApiOrigins` enforcement for authenticated requests.
|
|
25
|
+
- Add a 0.4 migration guide and package provenance release workflow.
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
- Normalize Gouno, OAuth, empty, and invalid JSON API responses through the shared envelope parser.
|
|
29
|
+
- Make HttpOnly Cookie Session the default when `sessionMode` is omitted.
|
|
30
|
+
- Return a discriminated Cookie or legacy-token result from OAuth callbacks.
|
|
31
|
+
- Keep explicit legacy token sessions in memory only; page reload requires reauthentication.
|
|
32
|
+
|
|
33
|
+
### Security
|
|
34
|
+
- Fail closed when Web Crypto is unavailable instead of generating OAuth state and PKCE verifier values with `Math.random`.
|
|
35
|
+
- Stop writing access and refresh tokens to Web Storage or JavaScript cookies.
|
|
36
|
+
- Reject credentialed requests to untrusted origins and reject external or protocol-relative login/logout return paths.
|
|
37
|
+
|
|
38
|
+
## [0.3.0] - 2026-08-15
|
|
39
|
+
### Added
|
|
40
|
+
- Add `subscribe(listener)` to `GossoClient` so every SPA can observe the
|
|
41
|
+
cookie-session snapshot without maintaining a duplicate authentication store.
|
|
42
|
+
- Add `refreshIdentityRequests` for the GOSSO Admin SPA, whose protected API
|
|
43
|
+
requests are served by the same origin as the identity provider.
|
|
44
|
+
|
|
45
|
+
## [0.2.1] - 2026-08-14
|
|
46
|
+
### Fixed
|
|
47
|
+
- Select application and Gosso CSRF cookies by exact request target instead of cookie order.
|
|
48
|
+
- Recover an expired Gosso CSRF cookie before Cookie Session refresh, retry application requests once, and restart PKCE without redirect loops when refresh fails.
|
|
49
|
+
- Coordinate Cookie Session refresh within a page and across tabs using single-flight and Web Locks.
|
|
50
|
+
- Clear client state after logout only when Gosso confirms server-side session revocation.
|
|
51
|
+
|
|
9
52
|
## [0.2.0] - 2026-08-12
|
|
10
53
|
### Added
|
|
11
54
|
- Add opt-in `sessionMode: "cookie"` for HttpOnly Cookie-backed SPA sessions. It keeps access and refresh tokens out of JavaScript-accessible storage while preserving PKCE, MFA, passkeys and account-management APIs.
|
package/MIGRATING.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Migrating to 0.4
|
|
2
|
+
|
|
3
|
+
Version 0.4 makes HttpOnly Cookie Session the default. Omit `sessionMode`, or
|
|
4
|
+
set it to `cookie`. Gosso must be reachable over HTTPS and configured with an
|
|
5
|
+
exact credentialed CORS origin when it is not same-origin.
|
|
6
|
+
|
|
7
|
+
Cookie callbacks return `{ sessionMode: 'cookie', redirectTo }`; tokens are set
|
|
8
|
+
only by Gosso with `Set-Cookie` and are not available to JavaScript. Replace
|
|
9
|
+
code that reads `tokenSet`, Web Storage, or an access-token cookie with
|
|
10
|
+
`getSnapshot()`, `subscribe()`, and `apiFetch()`.
|
|
11
|
+
|
|
12
|
+
`sessionMode: 'token'` remains an explicit legacy option. Its tokens live only
|
|
13
|
+
in memory and disappear on reload. `apiFetch` sends credentials only to the
|
|
14
|
+
page origin, issuer origin, or an exact origin listed in `allowedApiOrigins`.
|
|
15
|
+
All login and logout return values must be application-local paths.
|
package/README.md
CHANGED
|
@@ -5,10 +5,12 @@ Browser SDK for Gosso OAuth/OIDC single-page application clients.
|
|
|
5
5
|
`@gosso/client` provides the protocol and account self-service layer for ordinary Gosso clients:
|
|
6
6
|
|
|
7
7
|
- Authorization Code + PKCE redirects and callback handling
|
|
8
|
-
-
|
|
9
|
-
- authenticated `apiFetch` with
|
|
8
|
+
- HttpOnly Cookie Session, userinfo loading, logout, and automatic refresh
|
|
9
|
+
- origin-restricted authenticated `apiFetch` with CSRF handling and 401 retry
|
|
10
10
|
- username/password login, MFA verification, and passkey login
|
|
11
11
|
- profile, password, email, MFA, passkey, and session management APIs
|
|
12
|
+
- password reset request and completion APIs
|
|
13
|
+
- typed API errors for consistent consumer handling
|
|
12
14
|
|
|
13
15
|
The package intentionally does not ship React UI. Build app-specific pages with your own design system and call the SDK methods underneath.
|
|
14
16
|
|
|
@@ -31,6 +33,8 @@ export const gossoClient = createGossoClient({
|
|
|
31
33
|
postLoginDefaultPath: '/admin',
|
|
32
34
|
loginPath: '/login',
|
|
33
35
|
storagePrefix: 'my-app',
|
|
36
|
+
sessionProfileEndpoint: '/api/me/session',
|
|
37
|
+
csrfCookieName: 'blog_csrf_token',
|
|
34
38
|
});
|
|
35
39
|
```
|
|
36
40
|
|
|
@@ -87,6 +91,9 @@ await gossoClient.confirmEmailChange(newEmail, code);
|
|
|
87
91
|
const mfaStatus = await gossoClient.getMfaStatus();
|
|
88
92
|
const passkeys = await gossoClient.listPasskeys();
|
|
89
93
|
const sessions = await gossoClient.listSessions();
|
|
94
|
+
|
|
95
|
+
await gossoClient.requestPasswordReset(email);
|
|
96
|
+
await gossoClient.resetPassword(resetToken, newPassword);
|
|
90
97
|
```
|
|
91
98
|
|
|
92
99
|
## Configuration
|
|
@@ -100,20 +107,38 @@ interface GossoClientConfig {
|
|
|
100
107
|
postLoginDefaultPath: string;
|
|
101
108
|
loginPath: string;
|
|
102
109
|
storagePrefix: string;
|
|
110
|
+
sessionMode?: 'token' | 'cookie';
|
|
111
|
+
allowedApiOrigins?: readonly string[];
|
|
112
|
+
sessionProfileEndpoint?: string;
|
|
113
|
+
csrfCookieName?: string;
|
|
103
114
|
fetchImpl?: typeof fetch;
|
|
104
115
|
onAuthRequired?: () => void;
|
|
105
116
|
onSessionChanged?: (snapshot: SessionSnapshot) => void;
|
|
106
117
|
}
|
|
107
118
|
```
|
|
108
119
|
|
|
109
|
-
|
|
120
|
+
Cookie Session is the default when `sessionMode` is omitted. Use a unique
|
|
121
|
+
`storagePrefix` for each SPA on the same origin to isolate transient PKCE,
|
|
122
|
+
profile, and refresh-coordination state.
|
|
123
|
+
|
|
124
|
+
`apiFetch` accepts the page origin and issuer origin by default. Add only exact,
|
|
125
|
+
trusted HTTPS origins to `allowedApiOrigins`; credentials are rejected before a
|
|
126
|
+
request is sent to any other origin.
|
|
127
|
+
|
|
128
|
+
In Cookie Session mode, `csrfCookieName` belongs to the application API only. Gosso identity requests always use `__Host-csrf_token` on HTTPS, or `csrf_token` only for an HTTP development issuer. Cookie lookup is exact and never depends on `document.cookie` order.
|
|
129
|
+
|
|
130
|
+
Gosso's default lifetimes are independent: Access Token 15 minutes, Refresh Token 168 hours, Session 24 hours, and CSRF Cookie 4 hours (capped at 24 hours). A missing CSRF Cookie does not invalidate the Refresh Token: the SDK first performs a safe session GET to recover Gosso's CSRF Cookie, then refreshes and retries the original application request once.
|
|
110
131
|
|
|
111
132
|
## Security Notes
|
|
112
133
|
|
|
113
134
|
- Use Authorization Code + PKCE for browser clients.
|
|
114
135
|
- Serve production clients over HTTPS.
|
|
115
136
|
- Keep the Gosso issuer and app behind a same-origin gateway when possible.
|
|
116
|
-
-
|
|
137
|
+
- Cookie Session is the secure default; access and refresh tokens remain in server-set `__Host-*` HttpOnly cookies and are never written by the SDK to Web Storage or JavaScript cookies.
|
|
138
|
+
- Explicit `sessionMode: "token"` is a legacy, tab-local mode. Tokens stay in memory, disappear on reload, and are sent only to configured origins.
|
|
139
|
+
- Cookie Session refresh is single-flight within a page and coordinated across tabs with the Web Locks API. Only a non-sensitive refresh generation marker is stored in `localStorage`.
|
|
140
|
+
- OAuth state and PKCE verifier generation requires Web Crypto and fails closed when a cryptographically secure random source is unavailable.
|
|
141
|
+
- Login and logout return locations must be application-local paths. See [MIGRATING.md](./MIGRATING.md) before upgrading from 0.3 or earlier.
|
|
117
142
|
|
|
118
143
|
## License
|
|
119
144
|
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
Only the latest minor version receives security fixes. Report vulnerabilities
|
|
4
|
+
through GitHub Security Advisories and do not disclose credentials or exploit
|
|
5
|
+
details in public issues. Include the affected version, impact, and a minimal
|
|
6
|
+
reproduction. Maintainers aim to acknowledge reports within seven days.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { AuthCallbackResult, AuthenticationResult, GossoClientConfig, LoginResult, MfaEnrollment, MfaStatus, PasskeyInfo, SessionInfo, SessionListener, SessionSnapshot, TokenResponse, UserProfile } from "./types.js";
|
|
2
|
+
export declare const defaultConfig: Pick<GossoClientConfig, "scope" | "postLoginDefaultPath" | "loginPath" | "storagePrefix" | "sessionMode">;
|
|
3
|
+
export declare function createGossoClient(inputConfig: GossoClientConfig): {
|
|
4
|
+
config: {
|
|
5
|
+
issuer: string;
|
|
6
|
+
sessionMode: "token" | "cookie" | undefined;
|
|
7
|
+
clientId: string;
|
|
8
|
+
redirectUri: string;
|
|
9
|
+
scope: string;
|
|
10
|
+
postLoginDefaultPath: string;
|
|
11
|
+
loginPath: string;
|
|
12
|
+
storagePrefix: string;
|
|
13
|
+
allowedApiOrigins?: readonly string[];
|
|
14
|
+
sessionProfileEndpoint?: string;
|
|
15
|
+
csrfCookieName?: string;
|
|
16
|
+
refreshIdentityRequests?: boolean;
|
|
17
|
+
fetchImpl?: typeof fetch;
|
|
18
|
+
onAuthRequired?: () => void;
|
|
19
|
+
onSessionChanged?: (snapshot: SessionSnapshot) => void;
|
|
20
|
+
};
|
|
21
|
+
storageKeys: {
|
|
22
|
+
accessToken: string;
|
|
23
|
+
refreshToken: string;
|
|
24
|
+
userProfile: string;
|
|
25
|
+
pkceVerifier: string;
|
|
26
|
+
authState: string;
|
|
27
|
+
postLoginRedirect: string;
|
|
28
|
+
tokenIssuedAt: string;
|
|
29
|
+
tokenExpiresIn: string;
|
|
30
|
+
refreshLock: string;
|
|
31
|
+
refreshGeneration: string;
|
|
32
|
+
authRedirectGuard: string;
|
|
33
|
+
};
|
|
34
|
+
getAccessToken: () => string | null;
|
|
35
|
+
getRefreshToken: () => string | null;
|
|
36
|
+
getUserProfile: () => UserProfile | null;
|
|
37
|
+
getSnapshot: () => SessionSnapshot;
|
|
38
|
+
subscribe: (listener: SessionListener) => () => void;
|
|
39
|
+
isLoggedIn: () => boolean;
|
|
40
|
+
isAdmin: () => boolean;
|
|
41
|
+
saveTokenSet: (data: TokenResponse | {
|
|
42
|
+
access_token: string;
|
|
43
|
+
refresh_token?: string;
|
|
44
|
+
expires_in?: number;
|
|
45
|
+
}) => void;
|
|
46
|
+
clear: () => void;
|
|
47
|
+
logout: (redirectTo?: string) => Promise<void>;
|
|
48
|
+
redirectToAuthorize: (customRedirectUri?: string) => Promise<void>;
|
|
49
|
+
exchangeCodeForToken: (code: string, state: string) => Promise<AuthenticationResult>;
|
|
50
|
+
handleRedirectCallback: (code: string, state: string) => Promise<AuthCallbackResult>;
|
|
51
|
+
fetchUserProfile: (accessToken?: string | null) => Promise<UserProfile>;
|
|
52
|
+
refreshAccessToken: () => Promise<string>;
|
|
53
|
+
apiFetch: (url: string, options?: RequestInit) => Promise<Response>;
|
|
54
|
+
loginWithPassword: (username: string, password: string) => Promise<LoginResult>;
|
|
55
|
+
requestPasswordReset: (email: string) => Promise<void>;
|
|
56
|
+
resetPassword: (token: string, newPassword: string) => Promise<void>;
|
|
57
|
+
verifyMfa: (mfaToken: string, code: string, type?: "totp" | "passkey") => Promise<AuthenticationResult>;
|
|
58
|
+
loginWithPasskey: () => Promise<AuthenticationResult>;
|
|
59
|
+
updateProfile: (displayName: string) => Promise<UserProfile>;
|
|
60
|
+
changePassword: (currentPassword: string, newPassword: string) => Promise<void>;
|
|
61
|
+
requestEmailChange: (newEmail: string, password: string) => Promise<void>;
|
|
62
|
+
confirmEmailChange: (newEmail: string, code: string) => Promise<UserProfile>;
|
|
63
|
+
getMfaStatus: () => Promise<MfaStatus>;
|
|
64
|
+
enrollMfa: () => Promise<MfaEnrollment>;
|
|
65
|
+
activateMfa: (code: string) => Promise<string[]>;
|
|
66
|
+
disableMfa: (currentPassword: string) => Promise<void>;
|
|
67
|
+
generateBackupCodes: () => Promise<string[]>;
|
|
68
|
+
listPasskeys: () => Promise<PasskeyInfo[]>;
|
|
69
|
+
registerPasskey: (name: string) => Promise<void>;
|
|
70
|
+
deletePasskey: (id: string) => Promise<void>;
|
|
71
|
+
listSessions: () => Promise<SessionInfo[]>;
|
|
72
|
+
getCurrentSession: () => Promise<SessionInfo>;
|
|
73
|
+
revokeSession: (id: string) => Promise<void>;
|
|
74
|
+
};
|
|
75
|
+
export type GossoClient = ReturnType<typeof createGossoClient>;
|
|
76
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,EACX,aAAa,EACb,SAAS,EAET,WAAW,EAEX,WAAW,EACX,eAAe,EACf,eAAe,EACf,aAAa,EACb,WAAW,EACZ,MAAM,YAAY,CAAC;AA+BpB,eAAO,MAAM,aAAa,EAAE,IAAI,CAC9B,iBAAiB,EACf,OAAO,GACP,sBAAsB,GACtB,WAAW,GACX,eAAe,GACf,aAAa,CAOhB,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BA8CnC,MAAM,GAAG,IAAI;2BAEZ,MAAM,GAAG,IAAI;0BAZjB,WAAW,GAAG,IAAI;uBAelB,eAAe;0BAwBV,eAAe;;;yBAStC,aAAa,GACb;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;;;8CAqapB,MAAM;iCAwBrD,MAAM,SACL,MAAM,KACZ,OAAO,CAAC,oBAAoB,CAAC;mCA0CxB,MAAM,SACL,MAAM,KACZ,OAAO,CAAC,kBAAkB,CAAC;uDArO3B,OAAO,CAAC,WAAW,CAAC;8BA9Dc,OAAO,CAAC,MAAM,CAAC;oBAkH7C,MAAM,YACF,WAAW,KACnB,OAAO,CAAC,QAAQ,CAAC;kCAqOR,MAAM,YACN,MAAM,KACf,OAAO,CAAC,WAAW,CAAC;kCAuBoB,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;2BAiBxD,MAAM,eACA,MAAM,KAClB,OAAO,CAAC,IAAI,CAAC;0BAcJ,MAAM,QACV,MAAM,SACN,MAAM,GAAG,SAAS,KACvB,OAAO,CAAC,oBAAoB,CAAC;4BAqBG,OAAO,CAAC,oBAAoB,CAAC;iCAuEtB,MAAM;sCAW7B,MAAM,eACV,MAAM;mCAgBuB,MAAM,YAAY,MAAM;mCAexB,MAAM,QAAQ,MAAM;wBAgBjC,OAAO,CAAC,SAAS,CAAC;qBAKrB,OAAO,CAAC,aAAa,CAAC;wBAOjB,MAAM,KAAG,OAAO,CAAC,MAAM,EAAE,CAAC;kCAqBhB,MAAM;+BASX,OAAO,CAAC,MAAM,EAAE,CAAC;wBAYxB,OAAO,CAAC,WAAW,EAAE,CAAC;4BAQhB,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;wBAkE1B,MAAM;wBAOR,OAAO,CAAC,WAAW,EAAE,CAAC;6BAajB,OAAO,CAAC,WAAW,CAAC;wBAQvB,MAAM;EAiDxC;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
|