@passkeykit/sso 1.0.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 +155 -0
- package/dist/index.d.ts +79 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +180 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -0
package/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# @passkeykit/sso
|
|
2
|
+
|
|
3
|
+
SSO client library for DanielTech satellite apps. Provides session management, inactivity tracking, SSO callback handling, and admin elevation — all configurable via a single factory function.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @passkeykit/sso
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { createSSOClient } from '@passkeykit/sso';
|
|
15
|
+
|
|
16
|
+
const sso = createSSOClient({
|
|
17
|
+
verifyUrl: 'https://push.danieltech.dev/api/auth/sso-verify',
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Configuration
|
|
22
|
+
|
|
23
|
+
| Option | Type | Default | Description |
|
|
24
|
+
|---|---|---|---|
|
|
25
|
+
| `verifyUrl` | `string` | **required** | Token verification endpoint URL |
|
|
26
|
+
| `ssoUrl` | `string` | `https://user.danieltech.dev` | SSO login page URL |
|
|
27
|
+
| `callbackPath` | `string` | `/auth/callback` | Callback path on your app |
|
|
28
|
+
| `sessionDuration` | `number` | 30 days (ms) | Absolute session lifetime |
|
|
29
|
+
| `inactivityTimeout` | `number` | `Infinity` | Idle timeout before re-auth (ms). Set `0` or `Infinity` to disable |
|
|
30
|
+
| `sessionKey` | `string` | `sso_session` | localStorage key for session data |
|
|
31
|
+
| `activityKey` | `string` | `sso_last_activity` | localStorage key for activity timestamp |
|
|
32
|
+
| `elevationDuration` | `number` | 15 min (ms) | Duration of admin elevation after re-auth |
|
|
33
|
+
|
|
34
|
+
### Per-App Examples
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
// Meds — 5h inactivity, custom callback path
|
|
38
|
+
const sso = createSSOClient({
|
|
39
|
+
verifyUrl: 'https://push.danieltech.dev/api/auth/sso-verify',
|
|
40
|
+
callbackPath: '/?sso_callback=1',
|
|
41
|
+
inactivityTimeout: 5 * 60 * 60 * 1000,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Groceries — 12h inactivity
|
|
45
|
+
const sso = createSSOClient({
|
|
46
|
+
verifyUrl: 'https://push.danieltech.dev/api/auth/sso-verify',
|
|
47
|
+
inactivityTimeout: 12 * 60 * 60 * 1000,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// MediaBox — no inactivity timeout (default)
|
|
51
|
+
const sso = createSSOClient({
|
|
52
|
+
verifyUrl: 'https://push.danieltech.dev/api/auth/sso-verify',
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## API
|
|
57
|
+
|
|
58
|
+
### `createSSOClient(config): SSOClient`
|
|
59
|
+
|
|
60
|
+
Returns an `SSOClient` with the following methods:
|
|
61
|
+
|
|
62
|
+
#### Session
|
|
63
|
+
|
|
64
|
+
- **`getSession(): SSOSession | null`** — Returns the current session, or `null` if expired or inactive.
|
|
65
|
+
- **`clearSession(): void`** — Removes session and activity data from localStorage.
|
|
66
|
+
- **`redirectToSSO(): void`** — Redirects the browser to the SSO login page with the correct callback URL.
|
|
67
|
+
- **`handleSSOCallback(token: string): Promise<SSOSession | null>`** — Verifies a JWT token via the `verifyUrl` endpoint, stores the session, and returns it.
|
|
68
|
+
|
|
69
|
+
#### Activity Tracking
|
|
70
|
+
|
|
71
|
+
- **`touchActivity(): void`** — Records current timestamp as last activity.
|
|
72
|
+
- **`startActivityTracking(): () => void`** — Listens for `pointerdown`, `keydown`, and `scroll` events (30s throttle). Returns a cleanup function.
|
|
73
|
+
|
|
74
|
+
#### Admin Elevation
|
|
75
|
+
|
|
76
|
+
- **`isElevated(): boolean`** — Checks if the current admin session has been elevated (re-authenticated).
|
|
77
|
+
- **`elevateSession(): void`** — Redirects to SSO for re-authentication with an elevation flag.
|
|
78
|
+
- **`completeElevation(): boolean`** — Call after SSO callback to finalize elevation. Returns `true` if elevation was completed.
|
|
79
|
+
- **`stepDown(): void`** — Drops the elevated status.
|
|
80
|
+
|
|
81
|
+
### Types
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
interface SSOSession {
|
|
85
|
+
userId: string;
|
|
86
|
+
name: string;
|
|
87
|
+
email: string;
|
|
88
|
+
role: string;
|
|
89
|
+
token: string;
|
|
90
|
+
expires: number;
|
|
91
|
+
elevated?: boolean;
|
|
92
|
+
elevatedUntil?: number;
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Integration Pattern
|
|
97
|
+
|
|
98
|
+
Replace your app's inline `src/lib/sso.ts` with a thin wrapper:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
// src/lib/sso.ts
|
|
102
|
+
import { createSSOClient } from '@passkeykit/sso';
|
|
103
|
+
|
|
104
|
+
const PUSH_URL = import.meta.env.VITE_PUSH_URL || 'https://push.danieltech.dev';
|
|
105
|
+
|
|
106
|
+
export const sso = createSSOClient({
|
|
107
|
+
verifyUrl: `${PUSH_URL}/api/auth/sso-verify`,
|
|
108
|
+
inactivityTimeout: 5 * 60 * 60 * 1000, // app-specific
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Re-export for convenience
|
|
112
|
+
export type { SSOSession, SSOClient } from '@passkeykit/sso';
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Then update imports:
|
|
116
|
+
|
|
117
|
+
```diff
|
|
118
|
+
- import { getSession, redirectToSSO } from '@/lib/sso';
|
|
119
|
+
+ import { sso } from '@/lib/sso';
|
|
120
|
+
+ // use sso.getSession(), sso.redirectToSSO(), etc.
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Or re-export individual functions:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
// src/lib/sso.ts
|
|
127
|
+
import { createSSOClient } from '@passkeykit/sso';
|
|
128
|
+
export type { SSOSession } from '@passkeykit/sso';
|
|
129
|
+
|
|
130
|
+
const PUSH_URL = import.meta.env.VITE_PUSH_URL || 'https://push.danieltech.dev';
|
|
131
|
+
|
|
132
|
+
const sso = createSSOClient({
|
|
133
|
+
verifyUrl: `${PUSH_URL}/api/auth/sso-verify`,
|
|
134
|
+
inactivityTimeout: 5 * 60 * 60 * 1000,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
export const {
|
|
138
|
+
getSession,
|
|
139
|
+
clearSession,
|
|
140
|
+
redirectToSSO,
|
|
141
|
+
handleSSOCallback,
|
|
142
|
+
touchActivity,
|
|
143
|
+
startActivityTracking,
|
|
144
|
+
isElevated,
|
|
145
|
+
elevateSession,
|
|
146
|
+
completeElevation,
|
|
147
|
+
stepDown,
|
|
148
|
+
} = sso;
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
This approach preserves existing import signatures so no other files need changes.
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @passkeykit/sso — SSO client for DanielTech satellite apps.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { createSSOClient } from '@passkeykit/sso';
|
|
6
|
+
* const sso = createSSOClient({ verifyUrl: 'https://push.danieltech.dev/api/auth/sso-verify' });
|
|
7
|
+
* // or with inactivity timeout:
|
|
8
|
+
* const sso = createSSOClient({ verifyUrl: '...', inactivityTimeout: 5 * 60 * 60 * 1000 });
|
|
9
|
+
*/
|
|
10
|
+
export interface SSOSession {
|
|
11
|
+
userId: string;
|
|
12
|
+
name: string;
|
|
13
|
+
email: string;
|
|
14
|
+
role: string;
|
|
15
|
+
token: string;
|
|
16
|
+
expires: number;
|
|
17
|
+
elevated?: boolean;
|
|
18
|
+
elevatedUntil?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface SSOClientConfig {
|
|
21
|
+
/** URL of the SSO login page. Defaults to 'https://user.danieltech.dev'. */
|
|
22
|
+
ssoUrl?: string;
|
|
23
|
+
/** URL of the token verification endpoint. Required. */
|
|
24
|
+
verifyUrl: string;
|
|
25
|
+
/** Callback path on the satellite app. Defaults to '/auth/callback'. */
|
|
26
|
+
callbackPath?: string;
|
|
27
|
+
/** Absolute session duration in ms. Defaults to 30 days. */
|
|
28
|
+
sessionDuration?: number;
|
|
29
|
+
/** Inactivity timeout in ms. Set to 0 or Infinity to disable. Defaults to Infinity (disabled). */
|
|
30
|
+
inactivityTimeout?: number;
|
|
31
|
+
/** localStorage key for the session. Defaults to 'sso_session'. */
|
|
32
|
+
sessionKey?: string;
|
|
33
|
+
/** localStorage key for activity tracking. Defaults to 'sso_last_activity'. */
|
|
34
|
+
activityKey?: string;
|
|
35
|
+
/** Admin elevation duration in ms. Defaults to 15 minutes. */
|
|
36
|
+
elevationDuration?: number;
|
|
37
|
+
}
|
|
38
|
+
export interface SSOClient {
|
|
39
|
+
/** Get the current session, or null if expired/inactive. */
|
|
40
|
+
getSession(): SSOSession | null;
|
|
41
|
+
/** Clear the current session and activity data. */
|
|
42
|
+
clearSession(): void;
|
|
43
|
+
/** Redirect the browser to the SSO login page. */
|
|
44
|
+
redirectToSSO(): void;
|
|
45
|
+
/** Handle the SSO callback — verify token and store session. */
|
|
46
|
+
handleSSOCallback(token: string): Promise<SSOSession | null>;
|
|
47
|
+
/** Record user activity (for inactivity tracking). */
|
|
48
|
+
touchActivity(): void;
|
|
49
|
+
/** Start listening to DOM events for activity tracking. Returns cleanup fn. */
|
|
50
|
+
startActivityTracking(): () => void;
|
|
51
|
+
/** Check if the current admin session is elevated. */
|
|
52
|
+
isElevated(): boolean;
|
|
53
|
+
/** Redirect to SSO for admin elevation (re-auth). */
|
|
54
|
+
elevateSession(): void;
|
|
55
|
+
/** Complete an in-flight elevation after SSO callback. */
|
|
56
|
+
completeElevation(): boolean;
|
|
57
|
+
/** Drop admin elevation. */
|
|
58
|
+
stepDown(): void;
|
|
59
|
+
/** The resolved config. */
|
|
60
|
+
config: Required<SSOClientConfig>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Create a configured SSO client instance.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* // Minimal — no inactivity timeout
|
|
67
|
+
* const sso = createSSOClient({
|
|
68
|
+
* verifyUrl: 'https://push.danieltech.dev/api/auth/sso-verify',
|
|
69
|
+
* });
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* // With 5-hour inactivity timeout
|
|
73
|
+
* const sso = createSSOClient({
|
|
74
|
+
* verifyUrl: 'https://push.danieltech.dev/api/auth/sso-verify',
|
|
75
|
+
* inactivityTimeout: 5 * 60 * 60 * 1000,
|
|
76
|
+
* });
|
|
77
|
+
*/
|
|
78
|
+
export declare function createSSOClient(userConfig: SSOClientConfig): SSOClient;
|
|
79
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kGAAkG;IAClG,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAYD,MAAM,WAAW,SAAS;IACxB,4DAA4D;IAC5D,UAAU,IAAI,UAAU,GAAG,IAAI,CAAC;IAChC,mDAAmD;IACnD,YAAY,IAAI,IAAI,CAAC;IACrB,kDAAkD;IAClD,aAAa,IAAI,IAAI,CAAC;IACtB,gEAAgE;IAChE,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAC7D,sDAAsD;IACtD,aAAa,IAAI,IAAI,CAAC;IACtB,+EAA+E;IAC/E,qBAAqB,IAAI,MAAM,IAAI,CAAC;IACpC,sDAAsD;IACtD,UAAU,IAAI,OAAO,CAAC;IACtB,qDAAqD;IACrD,cAAc,IAAI,IAAI,CAAC;IACvB,0DAA0D;IAC1D,iBAAiB,IAAI,OAAO,CAAC;IAC7B,4BAA4B;IAC5B,QAAQ,IAAI,IAAI,CAAC;IACjB,2BAA2B;IAC3B,MAAM,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;CACnC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,eAAe,GAAG,SAAS,CAuJtE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @passkeykit/sso — SSO client for DanielTech satellite apps.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { createSSOClient } from '@passkeykit/sso';
|
|
6
|
+
* const sso = createSSOClient({ verifyUrl: 'https://push.danieltech.dev/api/auth/sso-verify' });
|
|
7
|
+
* // or with inactivity timeout:
|
|
8
|
+
* const sso = createSSOClient({ verifyUrl: '...', inactivityTimeout: 5 * 60 * 60 * 1000 });
|
|
9
|
+
*/
|
|
10
|
+
const DEFAULTS = {
|
|
11
|
+
ssoUrl: "https://user.danieltech.dev",
|
|
12
|
+
callbackPath: "/auth/callback",
|
|
13
|
+
sessionDuration: 30 * 24 * 60 * 60 * 1000,
|
|
14
|
+
inactivityTimeout: Infinity,
|
|
15
|
+
sessionKey: "sso_session",
|
|
16
|
+
activityKey: "sso_last_activity",
|
|
17
|
+
elevationDuration: 15 * 60 * 1000,
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Create a configured SSO client instance.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // Minimal — no inactivity timeout
|
|
24
|
+
* const sso = createSSOClient({
|
|
25
|
+
* verifyUrl: 'https://push.danieltech.dev/api/auth/sso-verify',
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // With 5-hour inactivity timeout
|
|
30
|
+
* const sso = createSSOClient({
|
|
31
|
+
* verifyUrl: 'https://push.danieltech.dev/api/auth/sso-verify',
|
|
32
|
+
* inactivityTimeout: 5 * 60 * 60 * 1000,
|
|
33
|
+
* });
|
|
34
|
+
*/
|
|
35
|
+
export function createSSOClient(userConfig) {
|
|
36
|
+
const cfg = {
|
|
37
|
+
ssoUrl: userConfig.ssoUrl ?? DEFAULTS.ssoUrl,
|
|
38
|
+
verifyUrl: userConfig.verifyUrl,
|
|
39
|
+
callbackPath: userConfig.callbackPath ?? DEFAULTS.callbackPath,
|
|
40
|
+
sessionDuration: userConfig.sessionDuration ?? DEFAULTS.sessionDuration,
|
|
41
|
+
inactivityTimeout: userConfig.inactivityTimeout ?? DEFAULTS.inactivityTimeout,
|
|
42
|
+
sessionKey: userConfig.sessionKey ?? DEFAULTS.sessionKey,
|
|
43
|
+
activityKey: userConfig.activityKey ?? DEFAULTS.activityKey,
|
|
44
|
+
elevationDuration: userConfig.elevationDuration ?? DEFAULTS.elevationDuration,
|
|
45
|
+
};
|
|
46
|
+
function getSession() {
|
|
47
|
+
try {
|
|
48
|
+
const raw = localStorage.getItem(cfg.sessionKey);
|
|
49
|
+
if (!raw)
|
|
50
|
+
return null;
|
|
51
|
+
const session = JSON.parse(raw);
|
|
52
|
+
// Absolute expiry
|
|
53
|
+
if (Date.now() > session.expires) {
|
|
54
|
+
clearSession();
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
// Inactivity check
|
|
58
|
+
if (cfg.inactivityTimeout !== Infinity && cfg.inactivityTimeout > 0) {
|
|
59
|
+
const last = localStorage.getItem(cfg.activityKey);
|
|
60
|
+
if (last && Date.now() - Number(last) > cfg.inactivityTimeout) {
|
|
61
|
+
clearSession();
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return session;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
clearSession();
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function clearSession() {
|
|
73
|
+
localStorage.removeItem(cfg.sessionKey);
|
|
74
|
+
localStorage.removeItem(cfg.activityKey);
|
|
75
|
+
}
|
|
76
|
+
function redirectToSSO() {
|
|
77
|
+
const callbackUrl = `${globalThis.location.origin}${cfg.callbackPath}`;
|
|
78
|
+
const loginUrl = `${cfg.ssoUrl}/login?callbackUrl=${encodeURIComponent(callbackUrl)}`;
|
|
79
|
+
globalThis.location.href = loginUrl;
|
|
80
|
+
}
|
|
81
|
+
async function handleSSOCallback(token) {
|
|
82
|
+
try {
|
|
83
|
+
const resp = await fetch(cfg.verifyUrl, {
|
|
84
|
+
method: "POST",
|
|
85
|
+
headers: { "Content-Type": "application/json" },
|
|
86
|
+
body: JSON.stringify({ token }),
|
|
87
|
+
});
|
|
88
|
+
if (!resp.ok)
|
|
89
|
+
return null;
|
|
90
|
+
const data = await resp.json();
|
|
91
|
+
if (!data.valid || !data.user)
|
|
92
|
+
return null;
|
|
93
|
+
const session = {
|
|
94
|
+
userId: data.user.id,
|
|
95
|
+
name: data.user.name,
|
|
96
|
+
email: data.user.email,
|
|
97
|
+
role: data.user.role || "member",
|
|
98
|
+
token,
|
|
99
|
+
expires: Date.now() + cfg.sessionDuration,
|
|
100
|
+
};
|
|
101
|
+
localStorage.setItem(cfg.sessionKey, JSON.stringify(session));
|
|
102
|
+
return session;
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function touchActivity() {
|
|
109
|
+
localStorage.setItem(cfg.activityKey, String(Date.now()));
|
|
110
|
+
}
|
|
111
|
+
function startActivityTracking() {
|
|
112
|
+
let timer = null;
|
|
113
|
+
const handler = () => {
|
|
114
|
+
if (timer)
|
|
115
|
+
return;
|
|
116
|
+
timer = setTimeout(() => { timer = null; }, 30000);
|
|
117
|
+
touchActivity();
|
|
118
|
+
};
|
|
119
|
+
touchActivity();
|
|
120
|
+
globalThis.addEventListener("pointerdown", handler);
|
|
121
|
+
globalThis.addEventListener("keydown", handler);
|
|
122
|
+
globalThis.addEventListener("scroll", handler, { passive: true });
|
|
123
|
+
return () => {
|
|
124
|
+
globalThis.removeEventListener("pointerdown", handler);
|
|
125
|
+
globalThis.removeEventListener("keydown", handler);
|
|
126
|
+
globalThis.removeEventListener("scroll", handler);
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
// ── Admin elevation ──────────────────────────────────────────────────
|
|
130
|
+
function isElevated() {
|
|
131
|
+
const session = getSession();
|
|
132
|
+
if (!session || session.role !== "admin")
|
|
133
|
+
return false;
|
|
134
|
+
return !!(session.elevated && session.elevatedUntil && Date.now() < session.elevatedUntil);
|
|
135
|
+
}
|
|
136
|
+
function elevateSession() {
|
|
137
|
+
const session = getSession();
|
|
138
|
+
if (!session || session.role !== "admin")
|
|
139
|
+
return;
|
|
140
|
+
localStorage.setItem("sso_elevate_pending", "true");
|
|
141
|
+
const callbackUrl = `${globalThis.location.origin}${cfg.callbackPath}`;
|
|
142
|
+
const loginUrl = `${cfg.ssoUrl}/login?callbackUrl=${encodeURIComponent(callbackUrl)}`;
|
|
143
|
+
globalThis.location.href = loginUrl;
|
|
144
|
+
}
|
|
145
|
+
function completeElevation() {
|
|
146
|
+
const pending = localStorage.getItem("sso_elevate_pending");
|
|
147
|
+
localStorage.removeItem("sso_elevate_pending");
|
|
148
|
+
if (!pending)
|
|
149
|
+
return false;
|
|
150
|
+
const session = getSession();
|
|
151
|
+
if (!session || session.role !== "admin")
|
|
152
|
+
return false;
|
|
153
|
+
session.elevated = true;
|
|
154
|
+
session.elevatedUntil = Date.now() + cfg.elevationDuration;
|
|
155
|
+
localStorage.setItem(cfg.sessionKey, JSON.stringify(session));
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
function stepDown() {
|
|
159
|
+
const session = getSession();
|
|
160
|
+
if (!session)
|
|
161
|
+
return;
|
|
162
|
+
session.elevated = false;
|
|
163
|
+
session.elevatedUntil = undefined;
|
|
164
|
+
localStorage.setItem(cfg.sessionKey, JSON.stringify(session));
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
getSession,
|
|
168
|
+
clearSession,
|
|
169
|
+
redirectToSSO,
|
|
170
|
+
handleSSOCallback,
|
|
171
|
+
touchActivity,
|
|
172
|
+
startActivityTracking,
|
|
173
|
+
isElevated,
|
|
174
|
+
elevateSession,
|
|
175
|
+
completeElevation,
|
|
176
|
+
stepDown,
|
|
177
|
+
config: cfg,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@passkeykit/sso",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "SSO client for DanielTech satellite apps — session management, activity tracking, and admin elevation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": ["dist", "README.md"],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/dnldev/passkey-kit.git",
|
|
22
|
+
"directory": "packages/sso"
|
|
23
|
+
},
|
|
24
|
+
"keywords": ["sso", "passkey", "webauthn", "session", "authentication"],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"typescript": "^5.9.3"
|
|
31
|
+
}
|
|
32
|
+
}
|