@sentroy-co/client-sdk 2.13.8 → 2.13.9
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/dist/auth/admin/index.d.ts +111 -10
- package/dist/auth/admin/index.d.ts.map +1 -1
- package/dist/auth/admin/index.js +125 -20
- package/dist/auth/admin/index.js.map +1 -1
- package/dist/auth/client.d.ts +127 -1
- package/dist/auth/client.d.ts.map +1 -1
- package/dist/auth/client.js +361 -3
- package/dist/auth/client.js.map +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/react/index.d.ts +63 -4
- package/dist/auth/react/index.d.ts.map +1 -1
- package/dist/auth/react/index.js +180 -1
- package/dist/auth/react/index.js.map +1 -1
- package/dist/auth/types.d.ts +55 -0
- package/dist/auth/types.d.ts.map +1 -1
- package/package.json +5 -1
- package/src/auth/admin/index.ts +227 -31
- package/src/auth/client.ts +438 -4
- package/src/auth/index.ts +9 -0
- package/src/auth/react/index.tsx +255 -4
- package/src/auth/types.ts +66 -0
package/dist/auth/react/index.js
CHANGED
|
@@ -4,11 +4,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
exports.SentroyAuthProvider = SentroyAuthProvider;
|
|
5
5
|
exports.useAuth = useAuth;
|
|
6
6
|
exports.useUser = useUser;
|
|
7
|
+
exports.useSessions = useSessions;
|
|
8
|
+
exports.useActivity = useActivity;
|
|
9
|
+
exports.useMfa = useMfa;
|
|
10
|
+
exports.usePasskeys = usePasskeys;
|
|
7
11
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
12
|
const react_1 = require("react");
|
|
9
13
|
const client_1 = require("../client");
|
|
10
14
|
const AuthContext = (0, react_1.createContext)(null);
|
|
11
|
-
function SentroyAuthProvider({ children, ...opts }) {
|
|
15
|
+
function SentroyAuthProvider({ children, autoConsumeFragment = true, ...opts }) {
|
|
12
16
|
// Single instance — opts deep-compare'a girersek dependency drift'i
|
|
13
17
|
// restart'a yol açar. Caller `projectSlug` değiştirmemeli runtime'da.
|
|
14
18
|
const auth = (0, react_1.useMemo)(() => new client_1.SentroyAuth(opts),
|
|
@@ -23,6 +27,19 @@ function SentroyAuthProvider({ children, ...opts }) {
|
|
|
23
27
|
});
|
|
24
28
|
return unsubscribe;
|
|
25
29
|
}, [auth]);
|
|
30
|
+
// Social login redirect handler — fragment varsa otomatik consume
|
|
31
|
+
(0, react_1.useEffect)(() => {
|
|
32
|
+
if (!autoConsumeFragment)
|
|
33
|
+
return;
|
|
34
|
+
if (typeof window === "undefined")
|
|
35
|
+
return;
|
|
36
|
+
if (!window.location.hash.includes("access_token="))
|
|
37
|
+
return;
|
|
38
|
+
auth.consumeRedirectFragment().catch(() => {
|
|
39
|
+
// Fragment varsa ama consume fail ise sessizce yut — caller
|
|
40
|
+
// gerekirse manuel tekrar dener.
|
|
41
|
+
});
|
|
42
|
+
}, [auth, autoConsumeFragment]);
|
|
26
43
|
const value = (0, react_1.useMemo)(() => ({
|
|
27
44
|
auth,
|
|
28
45
|
user,
|
|
@@ -32,6 +49,12 @@ function SentroyAuthProvider({ children, ...opts }) {
|
|
|
32
49
|
signOut: () => auth.signOut(),
|
|
33
50
|
sendPasswordReset: (e) => auth.sendPasswordReset(e),
|
|
34
51
|
verifyEmail: (t) => auth.verifyEmail(t),
|
|
52
|
+
verifyMfa: (i) => auth.verifyMfa(i),
|
|
53
|
+
sendMagicLink: (i) => auth.sendMagicLink(i),
|
|
54
|
+
consumeMagicLink: (t) => auth.consumeMagicLink(t),
|
|
55
|
+
acceptInvitation: (i) => auth.acceptInvitation(i),
|
|
56
|
+
socialAuthorizeUrl: (p, o) => auth.socialAuthorizeUrl(p, o),
|
|
57
|
+
consumeRedirectFragment: () => auth.consumeRedirectFragment(),
|
|
35
58
|
}), [auth, user, loading]);
|
|
36
59
|
return (0, jsx_runtime_1.jsx)(AuthContext.Provider, { value: value, children: children });
|
|
37
60
|
}
|
|
@@ -49,4 +72,160 @@ function useAuth() {
|
|
|
49
72
|
function useUser() {
|
|
50
73
|
return useAuth().user;
|
|
51
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Reactive sessions hook — `/me/sessions` çağırır, refresh trigger eden
|
|
77
|
+
* `refresh()` döner. Manual revoke sonrası caller `refresh()` çağırır.
|
|
78
|
+
*/
|
|
79
|
+
function useSessions() {
|
|
80
|
+
const { auth, user } = useAuth();
|
|
81
|
+
const [sessions, setSessions] = (0, react_1.useState)(null);
|
|
82
|
+
const [loading, setLoading] = (0, react_1.useState)(false);
|
|
83
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
84
|
+
const refresh = (0, react_1.useCallback)(async () => {
|
|
85
|
+
if (!user) {
|
|
86
|
+
setSessions(null);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
setLoading(true);
|
|
90
|
+
setError(null);
|
|
91
|
+
try {
|
|
92
|
+
const data = await auth.listSessions();
|
|
93
|
+
setSessions(data);
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
setLoading(false);
|
|
100
|
+
}
|
|
101
|
+
}, [auth, user]);
|
|
102
|
+
(0, react_1.useEffect)(() => {
|
|
103
|
+
refresh();
|
|
104
|
+
}, [refresh]);
|
|
105
|
+
const revoke = (0, react_1.useCallback)(async (id) => {
|
|
106
|
+
await auth.revokeSession(id);
|
|
107
|
+
await refresh();
|
|
108
|
+
}, [auth, refresh]);
|
|
109
|
+
return { sessions, loading, error, refresh, revoke };
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Reactive activity log hook — `/me/activity`. RP'nin "recent activity"
|
|
113
|
+
* tab'ı için.
|
|
114
|
+
*/
|
|
115
|
+
function useActivity() {
|
|
116
|
+
const { auth, user } = useAuth();
|
|
117
|
+
const [activity, setActivity] = (0, react_1.useState)(null);
|
|
118
|
+
const [loading, setLoading] = (0, react_1.useState)(false);
|
|
119
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
120
|
+
const refresh = (0, react_1.useCallback)(async () => {
|
|
121
|
+
if (!user) {
|
|
122
|
+
setActivity(null);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
setLoading(true);
|
|
126
|
+
setError(null);
|
|
127
|
+
try {
|
|
128
|
+
const data = await auth.getActivity();
|
|
129
|
+
setActivity(data);
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
setLoading(false);
|
|
136
|
+
}
|
|
137
|
+
}, [auth, user]);
|
|
138
|
+
(0, react_1.useEffect)(() => {
|
|
139
|
+
refresh();
|
|
140
|
+
}, [refresh]);
|
|
141
|
+
return { activity, loading, error, refresh };
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Reactive MFA status. enroll / verify / disable wrapper'ları, status
|
|
145
|
+
* otomatik yeniden çekilir.
|
|
146
|
+
*/
|
|
147
|
+
function useMfa() {
|
|
148
|
+
const { auth, user } = useAuth();
|
|
149
|
+
const [status, setStatus] = (0, react_1.useState)(null);
|
|
150
|
+
const [loading, setLoading] = (0, react_1.useState)(false);
|
|
151
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
152
|
+
const refresh = (0, react_1.useCallback)(async () => {
|
|
153
|
+
if (!user) {
|
|
154
|
+
setStatus(null);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
setLoading(true);
|
|
158
|
+
setError(null);
|
|
159
|
+
try {
|
|
160
|
+
const data = await auth.mfa.getStatus();
|
|
161
|
+
setStatus(data);
|
|
162
|
+
}
|
|
163
|
+
catch (e) {
|
|
164
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
165
|
+
}
|
|
166
|
+
finally {
|
|
167
|
+
setLoading(false);
|
|
168
|
+
}
|
|
169
|
+
}, [auth, user]);
|
|
170
|
+
(0, react_1.useEffect)(() => {
|
|
171
|
+
refresh();
|
|
172
|
+
}, [refresh]);
|
|
173
|
+
const verifyTotpEnrollment = (0, react_1.useCallback)(async (code) => {
|
|
174
|
+
await auth.mfa.verifyTotpEnrollment(code);
|
|
175
|
+
await refresh();
|
|
176
|
+
}, [auth, refresh]);
|
|
177
|
+
const disableTotp = (0, react_1.useCallback)(async (currentPassword) => {
|
|
178
|
+
await auth.mfa.disableTotp(currentPassword);
|
|
179
|
+
await refresh();
|
|
180
|
+
}, [auth, refresh]);
|
|
181
|
+
return {
|
|
182
|
+
status,
|
|
183
|
+
loading,
|
|
184
|
+
error,
|
|
185
|
+
refresh,
|
|
186
|
+
enrollTotp: () => auth.mfa.enrollTotp(),
|
|
187
|
+
verifyTotpEnrollment,
|
|
188
|
+
disableTotp,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Reactive passkey list — list/delete/register, mutation sonrası
|
|
193
|
+
* otomatik refresh.
|
|
194
|
+
*/
|
|
195
|
+
function usePasskeys() {
|
|
196
|
+
const { auth, user } = useAuth();
|
|
197
|
+
const [passkeys, setPasskeys] = (0, react_1.useState)(null);
|
|
198
|
+
const [loading, setLoading] = (0, react_1.useState)(false);
|
|
199
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
200
|
+
const refresh = (0, react_1.useCallback)(async () => {
|
|
201
|
+
if (!user) {
|
|
202
|
+
setPasskeys(null);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
setLoading(true);
|
|
206
|
+
setError(null);
|
|
207
|
+
try {
|
|
208
|
+
const data = await auth.passkey.list();
|
|
209
|
+
setPasskeys(data);
|
|
210
|
+
}
|
|
211
|
+
catch (e) {
|
|
212
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
setLoading(false);
|
|
216
|
+
}
|
|
217
|
+
}, [auth, user]);
|
|
218
|
+
(0, react_1.useEffect)(() => {
|
|
219
|
+
refresh();
|
|
220
|
+
}, [refresh]);
|
|
221
|
+
const register = (0, react_1.useCallback)(async (deviceName) => {
|
|
222
|
+
await auth.passkey.register(deviceName);
|
|
223
|
+
await refresh();
|
|
224
|
+
}, [auth, refresh]);
|
|
225
|
+
const remove = (0, react_1.useCallback)(async (id) => {
|
|
226
|
+
await auth.passkey.delete(id);
|
|
227
|
+
await refresh();
|
|
228
|
+
}, [auth, refresh]);
|
|
229
|
+
return { passkeys, loading, error, refresh, register, remove };
|
|
230
|
+
}
|
|
52
231
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/react/index.tsx"],"names":[],"mappings":";AAAA,YAAY,CAAA;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/react/index.tsx"],"names":[],"mappings":"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"}
|
package/dist/auth/types.d.ts
CHANGED
|
@@ -47,4 +47,59 @@ export declare class SentroyAuthError extends Error {
|
|
|
47
47
|
readonly status: number;
|
|
48
48
|
constructor(code: string, message: string, status: number);
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Login response when MFA is enrolled — first step returns mfaRequired+
|
|
52
|
+
* mfaToken; second step `verifyMfa(mfaToken, code)` issues final tokens.
|
|
53
|
+
*/
|
|
54
|
+
export interface MfaChallengeResponse {
|
|
55
|
+
mfaRequired: true;
|
|
56
|
+
mfaToken: string;
|
|
57
|
+
factorType: "totp";
|
|
58
|
+
}
|
|
59
|
+
/** Discriminated union — Login may resolve to tokens OR MFA challenge. */
|
|
60
|
+
export type LoginOutcome = {
|
|
61
|
+
kind: "tokens";
|
|
62
|
+
data: LoginResponse;
|
|
63
|
+
} | {
|
|
64
|
+
kind: "mfa";
|
|
65
|
+
data: MfaChallengeResponse;
|
|
66
|
+
};
|
|
67
|
+
export interface SessionSummary {
|
|
68
|
+
id: string;
|
|
69
|
+
refreshTokenPrefix: string;
|
|
70
|
+
userAgent: string | null;
|
|
71
|
+
ip: string | null;
|
|
72
|
+
expiresAt: string;
|
|
73
|
+
createdAt: string;
|
|
74
|
+
}
|
|
75
|
+
export interface ActivityEntry {
|
|
76
|
+
id: string;
|
|
77
|
+
action: string;
|
|
78
|
+
ipAddress: string | null;
|
|
79
|
+
createdAt: string;
|
|
80
|
+
details: Record<string, unknown> | null;
|
|
81
|
+
}
|
|
82
|
+
export interface MfaStatus {
|
|
83
|
+
enrolled: boolean;
|
|
84
|
+
factorType?: "totp";
|
|
85
|
+
verifiedAt?: string | null;
|
|
86
|
+
recoveryCodesRemaining?: number;
|
|
87
|
+
}
|
|
88
|
+
export interface MfaEnrollResponse {
|
|
89
|
+
secret: string;
|
|
90
|
+
otpauthUri: string;
|
|
91
|
+
}
|
|
92
|
+
export interface MfaVerifyEnrollmentResponse {
|
|
93
|
+
enrolled: true;
|
|
94
|
+
recoveryCodes: string[];
|
|
95
|
+
}
|
|
96
|
+
export interface PasskeySummary {
|
|
97
|
+
id: string;
|
|
98
|
+
credentialIdPrefix: string;
|
|
99
|
+
deviceName: string | null;
|
|
100
|
+
transports: string[];
|
|
101
|
+
lastUsedAt: string | null;
|
|
102
|
+
createdAt: string;
|
|
103
|
+
}
|
|
104
|
+
export type SocialProvider = "google" | "github" | "facebook" | "microsoft" | "twitter" | "apple";
|
|
50
105
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/auth/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,aAAa,EAAE,MAAM,CAAA;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,OAAO,CAAA;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,QAAQ,CAAA;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,eAAe,CAAA;IACrB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,QAAQ,CAAA;IACpB,yBAAyB,CAAC,EAAE,OAAO,CAAA;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,eAAe,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,QAAQ,CAAA;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,iBAAiB,EAAE,MAAM,CAAA;CAC1B;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;gBACX,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAM1D"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentroy-co/client-sdk",
|
|
3
|
-
"version": "2.13.
|
|
3
|
+
"version": "2.13.9",
|
|
4
4
|
"description": "TypeScript SDK + CLI for the Sentroy platform — mail, storage, env vault + React components.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -95,10 +95,14 @@
|
|
|
95
95
|
"node": ">=18.0.0"
|
|
96
96
|
},
|
|
97
97
|
"peerDependencies": {
|
|
98
|
+
"@simplewebauthn/browser": "^13.0.0",
|
|
98
99
|
"react": ">=18.0.0",
|
|
99
100
|
"react-dom": ">=18.0.0"
|
|
100
101
|
},
|
|
101
102
|
"peerDependenciesMeta": {
|
|
103
|
+
"@simplewebauthn/browser": {
|
|
104
|
+
"optional": true
|
|
105
|
+
},
|
|
102
106
|
"react": {
|
|
103
107
|
"optional": true
|
|
104
108
|
},
|
package/src/auth/admin/index.ts
CHANGED
|
@@ -1,34 +1,220 @@
|
|
|
1
1
|
import { AuthHttp } from "../http"
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
SentroyAuthUser,
|
|
4
|
+
SignupResponse,
|
|
5
|
+
LoginResponse,
|
|
6
|
+
LoginOutcome,
|
|
7
|
+
AuthTokensResponse,
|
|
8
|
+
MfaChallengeResponse,
|
|
9
|
+
} from "../types"
|
|
3
10
|
|
|
4
11
|
/**
|
|
5
12
|
* Server-side Sentroy Auth admin SDK. **Node only — apiKey browser'a
|
|
6
|
-
* koymayın**; bu sınıf Project'in master `aps_` token'ını taşır
|
|
7
|
-
* Sentroy üzerindeki user pool'a yetki vermez.
|
|
13
|
+
* koymayın**; bu sınıf Project'in master `aps_` token'ını taşır.
|
|
8
14
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
15
|
+
* Tüm public auth endpoint'lerini apiKey'le proxy eder ve JWT'yi local
|
|
16
|
+
* verify edebilir (JWKS cache + RSA Subtle). RP backend tipik akış:
|
|
17
|
+
*
|
|
18
|
+
* const admin = new SentroyAuthAdmin({ projectSlug, apiKey })
|
|
19
|
+
* const out = await admin.users.signIn({ email, password })
|
|
20
|
+
* if (out.kind === "tokens") setCookie(out.data.accessToken, ...)
|
|
21
|
+
* else // MFA flow
|
|
22
|
+
*
|
|
23
|
+
* // Mid-request: verify
|
|
24
|
+
* const claims = await admin.verifyIdToken(req.cookies.accessToken)
|
|
25
|
+
*
|
|
26
|
+
* Token persistence yok — server-side request-scoped; caller cookie /
|
|
27
|
+
* session / DB nereye isterse oraya yazar.
|
|
12
28
|
*/
|
|
13
29
|
|
|
14
30
|
export interface SentroyAuthAdminOptions {
|
|
15
31
|
authBaseUrl?: string
|
|
16
32
|
projectSlug: string
|
|
17
33
|
apiKey: string
|
|
34
|
+
/** JWKS cache TTL (saniye). Default 3600 (1 saat) — JWT rotation
|
|
35
|
+
* grace period'una uyumlu; daha agresif rotation yapan project'ler
|
|
36
|
+
* daha düşük set edebilir. */
|
|
37
|
+
jwksCacheTtl?: number
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface CachedJwks {
|
|
41
|
+
keys: Record<string, unknown>[]
|
|
42
|
+
expiresAt: number
|
|
18
43
|
}
|
|
19
44
|
|
|
20
45
|
export class SentroyAuthAdmin {
|
|
21
46
|
private readonly http: AuthHttp
|
|
22
|
-
private
|
|
47
|
+
private readonly jwksCacheTtl: number
|
|
48
|
+
private cachedJwks: CachedJwks | null = null
|
|
23
49
|
|
|
24
50
|
constructor(opts: SentroyAuthAdminOptions) {
|
|
25
51
|
this.http = new AuthHttp(opts)
|
|
52
|
+
this.jwksCacheTtl = opts.jwksCacheTtl ?? 3600
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get projectSlug(): string {
|
|
56
|
+
return this.http.projectSlug
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get baseUrl(): string {
|
|
60
|
+
return this.http.baseUrl
|
|
26
61
|
}
|
|
27
62
|
|
|
28
63
|
// ─── User pool admin ──────────────────────────────────────────────────
|
|
29
64
|
|
|
30
65
|
users = {
|
|
31
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Server-side signup proxy. apiKey backend'de — browser'a sızmaz.
|
|
68
|
+
* Email verification project config'ine bağlı: required ise
|
|
69
|
+
* `emailVerificationRequired: true` döner, tokens undefined.
|
|
70
|
+
*/
|
|
71
|
+
create: (input: {
|
|
72
|
+
email: string
|
|
73
|
+
password: string
|
|
74
|
+
displayName?: string
|
|
75
|
+
metadata?: Record<string, unknown>
|
|
76
|
+
}): Promise<SignupResponse> =>
|
|
77
|
+
this.http.request<SignupResponse>("/signup", {
|
|
78
|
+
method: "POST",
|
|
79
|
+
json: input,
|
|
80
|
+
}),
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Server-side login proxy. MFA-aware: tokens VEYA MFA challenge.
|
|
84
|
+
* RP backend `out.kind === "mfa"` ise kullanıcıdan code alıp
|
|
85
|
+
* `users.verifyMfa(...)` çağırır.
|
|
86
|
+
*/
|
|
87
|
+
signIn: async (input: {
|
|
88
|
+
email: string
|
|
89
|
+
password: string
|
|
90
|
+
rememberMe?: boolean
|
|
91
|
+
}): Promise<LoginOutcome> => {
|
|
92
|
+
const res = await this.http.request<
|
|
93
|
+
LoginResponse | MfaChallengeResponse
|
|
94
|
+
>("/login", { method: "POST", json: input })
|
|
95
|
+
if ("mfaRequired" in res && res.mfaRequired) {
|
|
96
|
+
return { kind: "mfa", data: res }
|
|
97
|
+
}
|
|
98
|
+
return { kind: "tokens", data: res as LoginResponse }
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
/** MFA verify ikinci adımı — `signIn` kind:"mfa" döndüyse. */
|
|
102
|
+
verifyMfa: (input: {
|
|
103
|
+
mfaToken: string
|
|
104
|
+
code?: string
|
|
105
|
+
recoveryCode?: string
|
|
106
|
+
}): Promise<LoginResponse> =>
|
|
107
|
+
this.http.request<LoginResponse>("/login/mfa/verify", {
|
|
108
|
+
method: "POST",
|
|
109
|
+
json: input,
|
|
110
|
+
}),
|
|
111
|
+
|
|
112
|
+
/** Refresh access token (rotation). Yeni refresh + access döner. */
|
|
113
|
+
refresh: (refreshToken: string): Promise<AuthTokensResponse> =>
|
|
114
|
+
this.http.request<AuthTokensResponse>("/refresh", {
|
|
115
|
+
method: "POST",
|
|
116
|
+
json: { refreshToken },
|
|
117
|
+
}),
|
|
118
|
+
|
|
119
|
+
/** Logout (refresh token revoke). */
|
|
120
|
+
signOut: (refreshToken: string): Promise<void> =>
|
|
121
|
+
this.http
|
|
122
|
+
.request<void>("/logout", {
|
|
123
|
+
method: "POST",
|
|
124
|
+
json: { refreshToken },
|
|
125
|
+
})
|
|
126
|
+
.then(() => undefined),
|
|
127
|
+
|
|
128
|
+
/** Verify email — link'ten gelen token. */
|
|
129
|
+
verifyEmail: (token: string): Promise<{ user: SentroyAuthUser }> =>
|
|
130
|
+
this.http.request<{ user: SentroyAuthUser }>("/verify-email", {
|
|
131
|
+
method: "POST",
|
|
132
|
+
json: { token },
|
|
133
|
+
}),
|
|
134
|
+
|
|
135
|
+
/** Password reset mail tetikle. */
|
|
136
|
+
requestPasswordReset: (email: string): Promise<void> =>
|
|
137
|
+
this.http
|
|
138
|
+
.request<void>("/password-reset/request", {
|
|
139
|
+
method: "POST",
|
|
140
|
+
json: { email },
|
|
141
|
+
})
|
|
142
|
+
.then(() => undefined),
|
|
143
|
+
|
|
144
|
+
/** Reset token + yeni şifre ile finalize. */
|
|
145
|
+
confirmPasswordReset: (input: {
|
|
146
|
+
token: string
|
|
147
|
+
newPassword: string
|
|
148
|
+
}): Promise<{ user: SentroyAuthUser }> =>
|
|
149
|
+
this.http.request<{ user: SentroyAuthUser }>("/password-reset/confirm", {
|
|
150
|
+
method: "POST",
|
|
151
|
+
json: input,
|
|
152
|
+
}),
|
|
153
|
+
|
|
154
|
+
/** Magic-link mail tetikle. */
|
|
155
|
+
sendMagicLink: (input: {
|
|
156
|
+
email: string
|
|
157
|
+
redirectUri?: string
|
|
158
|
+
}): Promise<void> =>
|
|
159
|
+
this.http
|
|
160
|
+
.request<void>("/magic-link/request", {
|
|
161
|
+
method: "POST",
|
|
162
|
+
json: input,
|
|
163
|
+
})
|
|
164
|
+
.then(() => undefined),
|
|
165
|
+
|
|
166
|
+
/** Magic-link token consume → login. */
|
|
167
|
+
consumeMagicLink: (token: string): Promise<LoginResponse> =>
|
|
168
|
+
this.http.request<LoginResponse>("/magic-link/consume", {
|
|
169
|
+
method: "POST",
|
|
170
|
+
json: { token },
|
|
171
|
+
}),
|
|
172
|
+
|
|
173
|
+
/** Davet token'ı ile yeni hesap + login. */
|
|
174
|
+
acceptInvitation: (input: {
|
|
175
|
+
token: string
|
|
176
|
+
password: string
|
|
177
|
+
displayName?: string
|
|
178
|
+
}): Promise<LoginResponse> =>
|
|
179
|
+
this.http.request<LoginResponse>("/invitation/accept", {
|
|
180
|
+
method: "POST",
|
|
181
|
+
json: input,
|
|
182
|
+
}),
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Access token ile remote /me — JWT'ye bağımlı kalmadan canlı
|
|
186
|
+
* profile çek. Token expire ise SentroyAuthError fırlatır.
|
|
187
|
+
*/
|
|
188
|
+
getUser: (accessToken: string): Promise<SentroyAuthUser> =>
|
|
189
|
+
this.http.request<SentroyAuthUser>("/me", {
|
|
190
|
+
method: "GET",
|
|
191
|
+
bearer: accessToken,
|
|
192
|
+
}),
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Token bazlı userinfo (OIDC tarzı). `/userinfo` claims response —
|
|
196
|
+
* SentroyAuthUser shape'inden daha minimal olabilir.
|
|
197
|
+
*/
|
|
198
|
+
getUserinfo: (
|
|
199
|
+
accessToken: string,
|
|
200
|
+
): Promise<{
|
|
201
|
+
sub: string
|
|
202
|
+
email?: string
|
|
203
|
+
email_verified?: boolean
|
|
204
|
+
name?: string
|
|
205
|
+
picture?: string
|
|
206
|
+
}> =>
|
|
207
|
+
this.http.request("/userinfo", {
|
|
208
|
+
method: "GET",
|
|
209
|
+
bearer: accessToken,
|
|
210
|
+
}),
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Admin list (paginated). **Şu an public API yok** — dashboard
|
|
214
|
+
* cookie-auth `/api/companies/[slug]/auth-projects/[id]/users`
|
|
215
|
+
* kullan. v2'de stk_ token'lı admin endpoint açılacak.
|
|
216
|
+
*/
|
|
217
|
+
list: (_opts: {
|
|
32
218
|
limit?: number
|
|
33
219
|
skip?: number
|
|
34
220
|
emailVerified?: boolean
|
|
@@ -39,18 +225,19 @@ export class SentroyAuthAdmin {
|
|
|
39
225
|
throw new Error(
|
|
40
226
|
"admin.users.list requires session-authenticated admin API; use dashboard /api/companies/[slug]/auth-projects/[id]/users instead. (v2 admin SDK will proxy this with stk_ tokens.)",
|
|
41
227
|
)
|
|
42
|
-
// NOTE Phase 5+: SDK admin endpoint'leri public path'lere taşınmadı;
|
|
43
|
-
// şu an `/api/companies/...` cookie-auth ile. v2'de `/api/v1/admin/...`
|
|
44
|
-
// RP token'ı ile authenticate eden ayrı public admin layer eklenir.
|
|
45
228
|
},
|
|
46
229
|
}
|
|
47
230
|
|
|
48
231
|
// ─── ID token verification ─────────────────────────────────────────────
|
|
49
232
|
|
|
50
233
|
/**
|
|
51
|
-
* Local verify — JWKS cache'lenir (
|
|
52
|
-
* RS256 ile
|
|
53
|
-
* eşleşmesi de kontrol edilir.
|
|
234
|
+
* Local verify — JWKS cache'lenir (default 1h TTL, opts ile değişir),
|
|
235
|
+
* JWT signature RS256 ile WebCrypto Subtle üzerinden verify edilir.
|
|
236
|
+
* `iss`/`aud` claim eşleşmesi de kontrol edilir.
|
|
237
|
+
*
|
|
238
|
+
* Throw'lar: malformed JWT, expired, iss/aud mismatch, key not found,
|
|
239
|
+
* signature mismatch. Tipik kullanım `try/catch` içinde — fail ise
|
|
240
|
+
* 401 dön.
|
|
54
241
|
*/
|
|
55
242
|
async verifyIdToken(token: string): Promise<{
|
|
56
243
|
sub: string
|
|
@@ -62,6 +249,7 @@ export class SentroyAuthAdmin {
|
|
|
62
249
|
aud: string
|
|
63
250
|
iat: number
|
|
64
251
|
exp: number
|
|
252
|
+
[claim: string]: unknown
|
|
65
253
|
}> {
|
|
66
254
|
const parts = token.split(".")
|
|
67
255
|
if (parts.length !== 3) {
|
|
@@ -83,12 +271,14 @@ export class SentroyAuthAdmin {
|
|
|
83
271
|
if (typeof claims.exp !== "number" || claims.exp * 1000 < Date.now()) {
|
|
84
272
|
throw new Error("Token expired.")
|
|
85
273
|
}
|
|
86
|
-
// iss + aud check
|
|
87
274
|
const expectedIssSuffix = `/p/${this.http.projectSlug}`
|
|
88
|
-
if (
|
|
275
|
+
if (
|
|
276
|
+
typeof claims.iss !== "string" ||
|
|
277
|
+
!claims.iss.endsWith(expectedIssSuffix)
|
|
278
|
+
) {
|
|
89
279
|
throw new Error("Issuer mismatch.")
|
|
90
280
|
}
|
|
91
|
-
// aud == project apiKeyPrefix (12 chars
|
|
281
|
+
// aud == project apiKeyPrefix (first 12 chars of api key)
|
|
92
282
|
if (
|
|
93
283
|
typeof claims.aud !== "string" ||
|
|
94
284
|
!this.http.apiKey?.startsWith(claims.aud)
|
|
@@ -111,17 +301,22 @@ export class SentroyAuthAdmin {
|
|
|
111
301
|
return claims as never
|
|
112
302
|
}
|
|
113
303
|
|
|
304
|
+
/** JWKS cache'ini elle temizle (key rotation sonrası). */
|
|
305
|
+
invalidateJwksCache(): void {
|
|
306
|
+
this.cachedJwks = null
|
|
307
|
+
}
|
|
308
|
+
|
|
114
309
|
private async fetchJwks(): Promise<{ keys: Record<string, unknown>[] }> {
|
|
115
|
-
if (this.cachedJwks
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
this.
|
|
124
|
-
}
|
|
310
|
+
if (this.cachedJwks && this.cachedJwks.expiresAt > Date.now()) {
|
|
311
|
+
return { keys: this.cachedJwks.keys }
|
|
312
|
+
}
|
|
313
|
+
const jwks = await this.http.request<{
|
|
314
|
+
keys: Record<string, unknown>[]
|
|
315
|
+
}>("/jwks.json", { method: "GET" })
|
|
316
|
+
this.cachedJwks = {
|
|
317
|
+
keys: jwks.keys,
|
|
318
|
+
expiresAt: Date.now() + this.jwksCacheTtl * 1000,
|
|
319
|
+
}
|
|
125
320
|
return jwks
|
|
126
321
|
}
|
|
127
322
|
}
|
|
@@ -167,7 +362,9 @@ async function verifyRsaSignature(input: {
|
|
|
167
362
|
const subtle =
|
|
168
363
|
typeof crypto !== "undefined" && crypto.subtle ? crypto.subtle : null
|
|
169
364
|
if (!subtle) {
|
|
170
|
-
throw new Error(
|
|
365
|
+
throw new Error(
|
|
366
|
+
"Web Crypto unavailable — upgrade Node >= 18 or run in a browser.",
|
|
367
|
+
)
|
|
171
368
|
}
|
|
172
369
|
const key = await subtle.importKey(
|
|
173
370
|
"jwk",
|
|
@@ -176,9 +373,8 @@ async function verifyRsaSignature(input: {
|
|
|
176
373
|
false,
|
|
177
374
|
["verify"],
|
|
178
375
|
)
|
|
179
|
-
// Web Crypto types want ArrayBuffer-backed BufferSource.
|
|
180
|
-
//
|
|
181
|
-
// bytes are created fresh from base64 decode so ArrayBuffer-safe — cast.
|
|
376
|
+
// Web Crypto types want ArrayBuffer-backed BufferSource. Bytes are
|
|
377
|
+
// created fresh from base64 decode so they are ArrayBuffer-safe.
|
|
182
378
|
const sigBytes = base64UrlToBytes(input.sigB64) as Uint8Array
|
|
183
379
|
const dataBytes = new TextEncoder().encode(input.data) as Uint8Array
|
|
184
380
|
const ok = await subtle.verify(
|