@ghostly-solutions/auth 0.1.1 → 0.2.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/LICENSE +13 -0
- package/README.md +200 -71
- package/dist/{auth-client-CAHMjodm.d.ts → auth-client-Cdkp07ii.d.ts} +14 -6
- package/dist/{auth-sdk-error-DKM7PyKC.d.ts → auth-sdk-error-D3gsfK9d.d.ts} +0 -3
- package/dist/extension.d.ts +49 -0
- package/dist/extension.js +634 -0
- package/dist/extension.js.map +1 -0
- package/dist/index.d.ts +13 -19
- package/dist/index.js +106 -119
- package/dist/index.js.map +1 -1
- package/dist/next.d.ts +4 -27
- package/dist/next.js +125 -383
- package/dist/next.js.map +1 -1
- package/dist/react.d.ts +4 -20
- package/dist/react.js +129 -176
- package/dist/react.js.map +1 -1
- package/docs/api-reference.md +66 -89
- package/docs/architecture.md +28 -46
- package/docs/development-and-ci.md +15 -19
- package/docs/index.md +1 -15
- package/docs/integration-guide.md +54 -80
- package/docs/overview.md +27 -28
- package/package.json +15 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Proprietary License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Ghostly Solutions.
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
This repository and all source code, configuration, documentation, and related materials
|
|
7
|
+
are proprietary and confidential unless a separate written agreement states otherwise.
|
|
8
|
+
|
|
9
|
+
No permission is granted to use, copy, modify, distribute, sublicense, publish, or sell
|
|
10
|
+
any part of this repository without prior written authorization from Ghostly Solutions.
|
|
11
|
+
|
|
12
|
+
Third-party components included through declared package managers remain subject to their
|
|
13
|
+
own licenses.
|
package/README.md
CHANGED
|
@@ -1,42 +1,44 @@
|
|
|
1
1
|
# @ghostly-solutions/auth
|
|
2
2
|
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
3
5
|
Authentication SDK for Ghostly Solutions products.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
This repository contains the npm package that implements a browser-first OAuth redirect flow
|
|
8
|
+
backed by a server-owned cookie session. Client code does not parse callback tokens and does not
|
|
9
|
+
define auth route handlers.
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
Repository type: `lib-repo`.
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
- Typed core client with deterministic error codes.
|
|
11
|
-
- Dedicated callback flow with immediate token URL cleanup.
|
|
12
|
-
- Session state with lazy revalidation.
|
|
13
|
-
- Cross-tab synchronization via `BroadcastChannel`.
|
|
14
|
-
- React adapter (`AuthProvider`, `useAuth`).
|
|
15
|
-
- React callback helpers (`AuthCallbackHandler`, `useAuthCallbackRedirect`).
|
|
16
|
-
- React session gate (`AuthSessionGate`).
|
|
17
|
-
- Next adapter (server and client guards).
|
|
18
|
-
- Next Auth Kit with ready route handlers (`mock` or `proxy`) and server-session helpers.
|
|
13
|
+
## Architecture
|
|
19
14
|
|
|
20
|
-
|
|
15
|
+
Package entrypoints:
|
|
21
16
|
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
17
|
+
- `@ghostly-solutions/auth`: browser/core client
|
|
18
|
+
- `@ghostly-solutions/auth/react`: React provider and session gates
|
|
19
|
+
- `@ghostly-solutions/auth/next`: Next.js server helpers
|
|
20
|
+
- `@ghostly-solutions/auth/extension`: extension-oriented auth helpers
|
|
26
21
|
|
|
27
|
-
|
|
22
|
+
The SDK assumes a fixed Ghostly Auth API surface and keeps token handling server-owned.
|
|
28
23
|
|
|
29
|
-
|
|
30
|
-
- `@ghostly-solutions/auth/react`
|
|
31
|
-
- `@ghostly-solutions/auth/next`
|
|
24
|
+
## Stack
|
|
32
25
|
|
|
33
|
-
|
|
26
|
+
- TypeScript
|
|
27
|
+
- tsup
|
|
28
|
+
- Vitest
|
|
29
|
+
- Biome
|
|
30
|
+
- npm
|
|
31
|
+
|
|
32
|
+
## Build
|
|
33
|
+
|
|
34
|
+
Install and validate:
|
|
34
35
|
|
|
35
36
|
```bash
|
|
36
|
-
npm
|
|
37
|
+
npm ci
|
|
38
|
+
npm run check
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
Expanded commands:
|
|
40
42
|
|
|
41
43
|
```bash
|
|
42
44
|
npm run lint
|
|
@@ -45,65 +47,204 @@ npm run test
|
|
|
45
47
|
npm run build
|
|
46
48
|
```
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
Pack verification:
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
```bash
|
|
53
|
+
npm pack --dry-run
|
|
54
|
+
```
|
|
51
55
|
|
|
52
|
-
##
|
|
56
|
+
## Run
|
|
53
57
|
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
This repository does not start a long-running application by default.
|
|
59
|
+
|
|
60
|
+
For local manual exploration:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm run demo
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Bun is optional for local demo shortcuts only.
|
|
67
|
+
|
|
68
|
+
## Config
|
|
69
|
+
|
|
70
|
+
This package is configured by the consuming application at runtime, not by repository-level
|
|
71
|
+
environment files.
|
|
72
|
+
|
|
73
|
+
Core client configuration typically includes:
|
|
74
|
+
|
|
75
|
+
- `apiOrigin`
|
|
76
|
+
- `application`
|
|
77
|
+
- browser callback destination or extension auth hooks, depending on entrypoint
|
|
56
78
|
|
|
57
|
-
|
|
79
|
+
## Dependencies
|
|
58
80
|
|
|
59
|
-
|
|
60
|
-
|
|
81
|
+
- browser login/logout against Ghostly Auth API
|
|
82
|
+
- session bootstrap for React and Next.js apps
|
|
83
|
+
- server-side session access for Next.js
|
|
84
|
+
- extension auth helpers for tab-based or custom auth flows
|
|
61
85
|
|
|
62
|
-
|
|
63
|
-
|
|
86
|
+
Peer dependencies:
|
|
87
|
+
|
|
88
|
+
- `react >= 18`
|
|
89
|
+
- `react-dom >= 18`
|
|
90
|
+
|
|
91
|
+
Package artifacts are built from `src/` and published to npm. `dist/` and tarballs must not be
|
|
92
|
+
committed as release storage.
|
|
93
|
+
|
|
94
|
+
## CI
|
|
95
|
+
|
|
96
|
+
GitLab CI validates this repository through `.gitlab-ci.yml`.
|
|
97
|
+
|
|
98
|
+
Current pipeline contract:
|
|
99
|
+
|
|
100
|
+
- `validate`: lint + typecheck
|
|
101
|
+
- `test`: unit tests
|
|
102
|
+
- `build`: bundle build + pack verification
|
|
103
|
+
- `release`: tag-driven npm publish gate
|
|
104
|
+
|
|
105
|
+
Green pipeline means:
|
|
106
|
+
|
|
107
|
+
- `npm run lint`
|
|
108
|
+
- `npm run typecheck`
|
|
109
|
+
- `npm run test`
|
|
110
|
+
- `npm run build`
|
|
111
|
+
- `npm pack --dry-run`
|
|
112
|
+
|
|
113
|
+
## Release
|
|
114
|
+
|
|
115
|
+
The release artifact is the npm package `@ghostly-solutions/auth`.
|
|
116
|
+
|
|
117
|
+
Release path:
|
|
118
|
+
|
|
119
|
+
1. merge with green CI
|
|
120
|
+
2. create a semver tag
|
|
121
|
+
3. let GitLab CI publish through the tag-gated release job
|
|
122
|
+
|
|
123
|
+
Current published version can be verified with:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npm view @ghostly-solutions/auth version dist-tags --json
|
|
64
127
|
```
|
|
65
128
|
|
|
66
|
-
##
|
|
129
|
+
## Troubleshooting
|
|
130
|
+
|
|
131
|
+
- auth contract mismatch: verify the backend exposes the required `/oauth/*` routes
|
|
132
|
+
- session fetch fails in Next.js: confirm headers are forwarded into `requireNextServerSession`
|
|
133
|
+
- package publish blocked: verify npm auth token and protected branch/tag permissions in GitLab
|
|
134
|
+
- local bundle drift: run `npm run check && npm pack --dry-run`
|
|
135
|
+
|
|
136
|
+
## Ownership
|
|
137
|
+
|
|
138
|
+
- Repo owners: @kirill
|
|
67
139
|
|
|
68
|
-
|
|
140
|
+
## License
|
|
69
141
|
|
|
70
|
-
|
|
71
|
-
- `requireNextServerSession()`
|
|
72
|
-
- `createNextAuthRouteHandlers({ mode: "mock" | "proxy" })`
|
|
142
|
+
See [LICENSE](/home/winicred/ghostly-solutions/@ghostly-solutions__auth/LICENSE). Public package availability does not override repository license terms unless Ghostly Solutions publishes separate licensing terms.
|
|
73
143
|
|
|
74
|
-
|
|
144
|
+
## Runtime Contract
|
|
75
145
|
|
|
76
|
-
|
|
146
|
+
The SDK assumes a fixed auth surface on your auth gateway:
|
|
147
|
+
|
|
148
|
+
- `GET /oauth/authorize`
|
|
149
|
+
- `GET /oauth/callback/provider`
|
|
150
|
+
- `GET /oauth/session`
|
|
151
|
+
- `POST /oauth/refresh`
|
|
152
|
+
- `POST /oauth/logout`
|
|
153
|
+
|
|
154
|
+
If your backend does not expose this contract, the SDK is not a drop-in fit.
|
|
155
|
+
|
|
156
|
+
## Install
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
npm install @ghostly-solutions/auth
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Peer dependencies:
|
|
163
|
+
|
|
164
|
+
- `react >= 18`
|
|
165
|
+
- `react-dom >= 18`
|
|
166
|
+
|
|
167
|
+
## Core Usage
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
import { createAuthClient } from "@ghostly-solutions/auth";
|
|
171
|
+
|
|
172
|
+
const auth = createAuthClient({
|
|
173
|
+
apiOrigin: "https://api.ghostlysolutions.com",
|
|
174
|
+
application: "admin",
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
await auth.init();
|
|
178
|
+
const session = await auth.getSession();
|
|
179
|
+
|
|
180
|
+
if (!session) {
|
|
181
|
+
auth.login({ returnTo: window.location.pathname });
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## React Usage
|
|
77
186
|
|
|
78
187
|
```tsx
|
|
79
|
-
import {
|
|
188
|
+
import { AuthProvider, AuthSessionGate } from "@ghostly-solutions/auth/react";
|
|
80
189
|
|
|
81
|
-
export
|
|
190
|
+
export function App() {
|
|
82
191
|
return (
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
192
|
+
<AuthProvider
|
|
193
|
+
apiOrigin="https://api.ghostlysolutions.com"
|
|
194
|
+
application="admin"
|
|
195
|
+
>
|
|
196
|
+
<AuthSessionGate
|
|
197
|
+
loading={<div>Loading...</div>}
|
|
198
|
+
unauthorized={({ login }) => (
|
|
199
|
+
<button onClick={() => login({ returnTo: "/" })}>Sign in</button>
|
|
200
|
+
)}
|
|
201
|
+
authorized={(session) => <div>{session.email}</div>}
|
|
202
|
+
/>
|
|
203
|
+
</AuthProvider>
|
|
87
204
|
);
|
|
88
205
|
}
|
|
89
206
|
```
|
|
90
207
|
|
|
91
|
-
##
|
|
208
|
+
## Next.js Usage
|
|
209
|
+
|
|
210
|
+
Use the server helpers to resolve the current session from request headers.
|
|
92
211
|
|
|
93
212
|
```ts
|
|
94
|
-
import {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
await
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
213
|
+
import { requireNextServerSession } from "@ghostly-solutions/auth/next";
|
|
214
|
+
|
|
215
|
+
export async function getServerData(headers: Headers) {
|
|
216
|
+
const session = await requireNextServerSession({
|
|
217
|
+
headers,
|
|
218
|
+
apiOrigin: "https://api.ghostlysolutions.com",
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
return { actorId: session.id };
|
|
104
222
|
}
|
|
105
223
|
```
|
|
106
224
|
|
|
225
|
+
No Next.js route handlers are required.
|
|
226
|
+
|
|
227
|
+
## Extension Usage
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
import { createExtensionAuthClient } from "@ghostly-solutions/auth/extension";
|
|
231
|
+
|
|
232
|
+
const auth = createExtensionAuthClient({
|
|
233
|
+
apiOrigin: "https://api.ghostlysolutions.com",
|
|
234
|
+
application: "ghostguard-extension",
|
|
235
|
+
openAuthorizePage: async ({ authorizeUrl }) => {
|
|
236
|
+
await chrome.tabs.create({ url: authorizeUrl });
|
|
237
|
+
},
|
|
238
|
+
launchWebAuthFlow: async ({ authorizeUrl }) => {
|
|
239
|
+
await openAuthWindow(authorizeUrl);
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
await auth.loginWithTabFlow({
|
|
244
|
+
returnTo: "/oauth/complete",
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
107
248
|
## Documentation
|
|
108
249
|
|
|
109
250
|
- [Docs Index](./docs/index.md)
|
|
@@ -112,16 +253,4 @@ try {
|
|
|
112
253
|
- [Integration Guide](./docs/integration-guide.md)
|
|
113
254
|
- [Architecture](./docs/architecture.md)
|
|
114
255
|
- [Development and CI](./docs/development-and-ci.md)
|
|
115
|
-
|
|
116
|
-
## Interactive Demo
|
|
117
|
-
|
|
118
|
-
Run the simulated authentication page in this repository:
|
|
119
|
-
|
|
120
|
-
```bash
|
|
121
|
-
npm run demo
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
Then open `http://localhost:4100/` to test login, callback processing, session retrieval,
|
|
125
|
-
and logout.
|
|
126
|
-
|
|
127
|
-
Detailed demo docs: [demo/README.md](./demo/README.md).
|
|
256
|
+
- [Demo](./demo/README.md)
|
|
@@ -8,25 +8,33 @@ interface GhostlySession {
|
|
|
8
8
|
permissions: string[];
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
interface
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
interface AuthClientOptions {
|
|
12
|
+
apiOrigin?: string;
|
|
13
|
+
application?: string;
|
|
14
|
+
}
|
|
15
|
+
interface AuthInitOptions {
|
|
16
|
+
forceRefresh?: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface AuthInitResult {
|
|
19
|
+
session: GhostlySession | null;
|
|
20
|
+
status: "authenticated" | "unauthenticated";
|
|
14
21
|
}
|
|
15
22
|
interface LoginOptions {
|
|
16
23
|
returnTo?: string;
|
|
24
|
+
application?: string;
|
|
17
25
|
}
|
|
18
26
|
interface SessionRequestOptions {
|
|
19
27
|
forceRefresh?: boolean;
|
|
20
28
|
}
|
|
21
29
|
type SessionListener = (session: GhostlySession | null) => void;
|
|
22
30
|
interface AuthClient {
|
|
23
|
-
|
|
31
|
+
init(options?: AuthInitOptions): Promise<AuthInitResult>;
|
|
24
32
|
getSession(options?: SessionRequestOptions): Promise<GhostlySession | null>;
|
|
25
33
|
login(options?: LoginOptions): void;
|
|
26
34
|
logout(): Promise<void>;
|
|
27
|
-
|
|
35
|
+
refresh(): Promise<GhostlySession | null>;
|
|
28
36
|
requireSession(): Promise<GhostlySession>;
|
|
29
37
|
subscribe(listener: SessionListener): () => void;
|
|
30
38
|
}
|
|
31
39
|
|
|
32
|
-
export type { AuthClient as A, GhostlySession as G, LoginOptions as L,
|
|
40
|
+
export type { AuthClient as A, GhostlySession as G, LoginOptions as L, SessionListener as S, AuthClientOptions as a, AuthInitOptions as b, AuthInitResult as c, SessionRequestOptions as d };
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
declare const authErrorCode: {
|
|
2
|
-
readonly callbackMissingToken: "callback_missing_token";
|
|
3
|
-
readonly callbackInvalidToken: "callback_invalid_token";
|
|
4
|
-
readonly callbackValidationFailed: "callback_validation_failed";
|
|
5
2
|
readonly unauthorized: "unauthorized";
|
|
6
3
|
readonly networkError: "network_error";
|
|
7
4
|
readonly apiError: "api_error";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { G as GhostlySession, A as AuthClient, L as LoginOptions } from './auth-client-Cdkp07ii.js';
|
|
2
|
+
|
|
3
|
+
interface LaunchWebAuthFlowPayload {
|
|
4
|
+
authorizeUrl: string;
|
|
5
|
+
}
|
|
6
|
+
interface OpenAuthorizePagePayload {
|
|
7
|
+
authorizeUrl: string;
|
|
8
|
+
}
|
|
9
|
+
type PersistAccessToken = (token: ExtensionStoredAccessToken | null) => Promise<void> | void;
|
|
10
|
+
type ResolveSessionId = () => Promise<string | null>;
|
|
11
|
+
type RestoreAccessToken = (() => Promise<ExtensionStoredAccessToken | null>) | (() => ExtensionStoredAccessToken | null);
|
|
12
|
+
interface ExtensionAccessToken {
|
|
13
|
+
accessToken: string;
|
|
14
|
+
application: string;
|
|
15
|
+
expiresAt: string | null;
|
|
16
|
+
session: GhostlySession | null;
|
|
17
|
+
tokenType: string;
|
|
18
|
+
}
|
|
19
|
+
interface ExtensionAccessTokenRequestOptions {
|
|
20
|
+
forceRefresh?: boolean;
|
|
21
|
+
}
|
|
22
|
+
interface ExtensionStoredAccessToken extends ExtensionAccessToken {
|
|
23
|
+
}
|
|
24
|
+
interface ExtensionAuthClientOptions {
|
|
25
|
+
apiOrigin: string;
|
|
26
|
+
application?: string;
|
|
27
|
+
clearSessionId?: () => Promise<void> | void;
|
|
28
|
+
launchWebAuthFlow?: (payload: LaunchWebAuthFlowPayload) => Promise<void>;
|
|
29
|
+
openAuthorizePage?: (payload: OpenAuthorizePagePayload) => Promise<void>;
|
|
30
|
+
persistAccessToken?: PersistAccessToken;
|
|
31
|
+
resolveSessionId?: ResolveSessionId;
|
|
32
|
+
restoreAccessToken?: RestoreAccessToken;
|
|
33
|
+
}
|
|
34
|
+
interface ExtensionAuthClient extends AuthClient {
|
|
35
|
+
getAccessToken(options?: ExtensionAccessTokenRequestOptions): Promise<ExtensionAccessToken | null>;
|
|
36
|
+
loginWithTabFlow(options?: LoginOptions): Promise<void>;
|
|
37
|
+
loginWithWebAuthFlow(options?: LoginOptions): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
declare function createExtensionAuthClient(options: ExtensionAuthClientOptions): ExtensionAuthClient;
|
|
40
|
+
|
|
41
|
+
interface ChromeExtensionAuthClientOptions extends Omit<ExtensionAuthClientOptions, "clearSessionId" | "openAuthorizePage" | "persistAccessToken" | "resolveSessionId" | "restoreAccessToken"> {
|
|
42
|
+
accessTokenStorageKey?: string;
|
|
43
|
+
sessionCookieName?: string;
|
|
44
|
+
sessionStorageKey?: string;
|
|
45
|
+
tokenExpiresAtStorageKey?: string;
|
|
46
|
+
}
|
|
47
|
+
declare function createChromeExtensionAuthClient(options: ChromeExtensionAuthClientOptions): ExtensionAuthClient;
|
|
48
|
+
|
|
49
|
+
export { type ChromeExtensionAuthClientOptions, type ExtensionAccessToken, type ExtensionAccessTokenRequestOptions, type ExtensionAuthClient, type ExtensionAuthClientOptions, type ExtensionStoredAccessToken, createChromeExtensionAuthClient, createExtensionAuthClient };
|