@originals/auth 1.5.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/.turbo/turbo-build.log +1 -0
- package/dist/client/index.d.ts +22 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +22 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/turnkey-client.d.ts +53 -0
- package/dist/client/turnkey-client.d.ts.map +1 -0
- package/dist/client/turnkey-client.js +268 -0
- package/dist/client/turnkey-client.js.map +1 -0
- package/dist/client/turnkey-did-signer.d.ts +54 -0
- package/dist/client/turnkey-did-signer.d.ts.map +1 -0
- package/dist/client/turnkey-did-signer.js +125 -0
- package/dist/client/turnkey-did-signer.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/server/email-auth.d.ts +42 -0
- package/dist/server/email-auth.d.ts.map +1 -0
- package/dist/server/email-auth.js +187 -0
- package/dist/server/email-auth.js.map +1 -0
- package/dist/server/index.d.ts +22 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +22 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/jwt.d.ts +49 -0
- package/dist/server/jwt.d.ts.map +1 -0
- package/dist/server/jwt.js +113 -0
- package/dist/server/jwt.js.map +1 -0
- package/dist/server/middleware.d.ts +39 -0
- package/dist/server/middleware.d.ts.map +1 -0
- package/dist/server/middleware.js +110 -0
- package/dist/server/middleware.js.map +1 -0
- package/dist/server/turnkey-client.d.ts +24 -0
- package/dist/server/turnkey-client.d.ts.map +1 -0
- package/dist/server/turnkey-client.js +118 -0
- package/dist/server/turnkey-client.js.map +1 -0
- package/dist/server/turnkey-signer.d.ts +40 -0
- package/dist/server/turnkey-signer.d.ts.map +1 -0
- package/dist/server/turnkey-signer.js +121 -0
- package/dist/server/turnkey-signer.js.map +1 -0
- package/dist/types.d.ts +155 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +79 -0
- package/src/client/index.ts +37 -0
- package/src/client/turnkey-client.ts +340 -0
- package/src/client/turnkey-did-signer.ts +189 -0
- package/src/index.ts +32 -0
- package/src/server/email-auth.ts +258 -0
- package/src/server/index.ts +38 -0
- package/src/server/jwt.ts +154 -0
- package/src/server/middleware.ts +136 -0
- package/src/server/turnkey-client.ts +152 -0
- package/src/server/turnkey-signer.ts +170 -0
- package/src/types.ts +168 -0
- package/tests/index.test.ts +25 -0
- package/tsconfig.json +28 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turnkey Email Authentication Service
|
|
3
|
+
* Implements email-based authentication using Turnkey's OTP flow
|
|
4
|
+
*/
|
|
5
|
+
import { Turnkey } from '@turnkey/sdk-server';
|
|
6
|
+
import type { EmailAuthSession, InitiateAuthResult, VerifyAuthResult } from '../types';
|
|
7
|
+
/**
|
|
8
|
+
* Session storage interface for pluggable session management
|
|
9
|
+
*/
|
|
10
|
+
export interface SessionStorage {
|
|
11
|
+
get(sessionId: string): EmailAuthSession | undefined;
|
|
12
|
+
set(sessionId: string, session: EmailAuthSession): void;
|
|
13
|
+
delete(sessionId: string): void;
|
|
14
|
+
cleanup(): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create an in-memory session storage
|
|
18
|
+
* For production, consider using Redis or a database
|
|
19
|
+
*/
|
|
20
|
+
export declare function createInMemorySessionStorage(): SessionStorage;
|
|
21
|
+
/**
|
|
22
|
+
* Initiate email authentication using Turnkey OTP
|
|
23
|
+
* Sends a 6-digit OTP code to the user's email
|
|
24
|
+
*/
|
|
25
|
+
export declare function initiateEmailAuth(email: string, turnkeyClient: Turnkey, sessionStorage?: SessionStorage): Promise<InitiateAuthResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Verify email authentication code using Turnkey OTP
|
|
28
|
+
*/
|
|
29
|
+
export declare function verifyEmailAuth(sessionId: string, code: string, turnkeyClient: Turnkey, sessionStorage?: SessionStorage): Promise<VerifyAuthResult>;
|
|
30
|
+
/**
|
|
31
|
+
* Check if a session is verified
|
|
32
|
+
*/
|
|
33
|
+
export declare function isSessionVerified(sessionId: string, sessionStorage?: SessionStorage): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Clean up a session after successful login
|
|
36
|
+
*/
|
|
37
|
+
export declare function cleanupSession(sessionId: string, sessionStorage?: SessionStorage): void;
|
|
38
|
+
/**
|
|
39
|
+
* Get session data
|
|
40
|
+
*/
|
|
41
|
+
export declare function getSession(sessionId: string, sessionStorage?: SessionStorage): EmailAuthSession | undefined;
|
|
42
|
+
//# sourceMappingURL=email-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-auth.d.ts","sourceRoot":"","sources":["../../src/server/email-auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAG9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAMvF;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAAC;IACrD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACxD,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,IAAI,cAAc,CA2B7D;AAmBD;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,OAAO,EACtB,cAAc,CAAC,EAAE,cAAc,GAC9B,OAAO,CAAC,kBAAkB,CAAC,CA2D7B;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,OAAO,EACtB,cAAc,CAAC,EAAE,cAAc,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CAqD3B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,cAAc,GAC9B,OAAO,CAYT;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,cAAc,GAC9B,IAAI,CAGN;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,cAAc,GAC9B,gBAAgB,GAAG,SAAS,CAa9B"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turnkey Email Authentication Service
|
|
3
|
+
* Implements email-based authentication using Turnkey's OTP flow
|
|
4
|
+
*/
|
|
5
|
+
import { sha256 } from '@noble/hashes/sha2.js';
|
|
6
|
+
import { bytesToHex } from '@noble/hashes/utils.js';
|
|
7
|
+
import { getOrCreateTurnkeySubOrg } from './turnkey-client';
|
|
8
|
+
// Session timeout (15 minutes to match Turnkey OTP)
|
|
9
|
+
const SESSION_TIMEOUT = 15 * 60 * 1000;
|
|
10
|
+
/**
|
|
11
|
+
* Create an in-memory session storage
|
|
12
|
+
* For production, consider using Redis or a database
|
|
13
|
+
*/
|
|
14
|
+
export function createInMemorySessionStorage() {
|
|
15
|
+
const sessions = new Map();
|
|
16
|
+
// Start cleanup interval
|
|
17
|
+
const cleanupInterval = setInterval(() => {
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
for (const [sessionId, session] of sessions.entries()) {
|
|
20
|
+
if (now - session.timestamp > SESSION_TIMEOUT) {
|
|
21
|
+
sessions.delete(sessionId);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}, 60 * 1000);
|
|
25
|
+
// Keep the interval from preventing process exit
|
|
26
|
+
if (cleanupInterval.unref) {
|
|
27
|
+
cleanupInterval.unref();
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
get: (sessionId) => sessions.get(sessionId),
|
|
31
|
+
set: (sessionId, session) => sessions.set(sessionId, session),
|
|
32
|
+
delete: (sessionId) => sessions.delete(sessionId),
|
|
33
|
+
cleanup: () => {
|
|
34
|
+
clearInterval(cleanupInterval);
|
|
35
|
+
sessions.clear();
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// Default session storage
|
|
40
|
+
let defaultSessionStorage = null;
|
|
41
|
+
function getDefaultSessionStorage() {
|
|
42
|
+
if (!defaultSessionStorage) {
|
|
43
|
+
defaultSessionStorage = createInMemorySessionStorage();
|
|
44
|
+
}
|
|
45
|
+
return defaultSessionStorage;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Generate a random session ID
|
|
49
|
+
*/
|
|
50
|
+
function generateSessionId() {
|
|
51
|
+
return `session_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Initiate email authentication using Turnkey OTP
|
|
55
|
+
* Sends a 6-digit OTP code to the user's email
|
|
56
|
+
*/
|
|
57
|
+
export async function initiateEmailAuth(email, turnkeyClient, sessionStorage) {
|
|
58
|
+
const storage = sessionStorage ?? getDefaultSessionStorage();
|
|
59
|
+
// Validate email format
|
|
60
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
61
|
+
if (!emailRegex.test(email)) {
|
|
62
|
+
throw new Error('Invalid email format');
|
|
63
|
+
}
|
|
64
|
+
console.log(`\n🚀 Initiating email auth for: ${email}`);
|
|
65
|
+
// Step 1: Get or create Turnkey sub-organization
|
|
66
|
+
const subOrgId = await getOrCreateTurnkeySubOrg(email, turnkeyClient);
|
|
67
|
+
// Step 2: Send OTP via Turnkey
|
|
68
|
+
console.log(`📨 Sending OTP to ${email} via Turnkey...`);
|
|
69
|
+
// Generate a unique user identifier for rate limiting
|
|
70
|
+
const data = new TextEncoder().encode(email);
|
|
71
|
+
const hash = sha256(data);
|
|
72
|
+
const userIdentifier = bytesToHex(hash);
|
|
73
|
+
const otpResult = await turnkeyClient.apiClient().initOtp({
|
|
74
|
+
otpType: 'OTP_TYPE_EMAIL',
|
|
75
|
+
contact: email,
|
|
76
|
+
userIdentifier: userIdentifier,
|
|
77
|
+
appName: 'Originals',
|
|
78
|
+
otpLength: 6,
|
|
79
|
+
alphanumeric: false,
|
|
80
|
+
});
|
|
81
|
+
const otpId = otpResult.otpId;
|
|
82
|
+
if (!otpId) {
|
|
83
|
+
throw new Error('Failed to initiate OTP - no OTP ID returned');
|
|
84
|
+
}
|
|
85
|
+
console.log(`✅ OTP sent! OTP ID: ${otpId}`);
|
|
86
|
+
// Create auth session
|
|
87
|
+
const sessionId = generateSessionId();
|
|
88
|
+
storage.set(sessionId, {
|
|
89
|
+
email,
|
|
90
|
+
subOrgId,
|
|
91
|
+
otpId,
|
|
92
|
+
timestamp: Date.now(),
|
|
93
|
+
verified: false,
|
|
94
|
+
});
|
|
95
|
+
console.log('='.repeat(60));
|
|
96
|
+
console.log(`📧 Check ${email} for the verification code!`);
|
|
97
|
+
console.log(` Session ID: ${sessionId}`);
|
|
98
|
+
console.log(` Valid for: 15 minutes`);
|
|
99
|
+
console.log('='.repeat(60) + '\n');
|
|
100
|
+
return {
|
|
101
|
+
sessionId,
|
|
102
|
+
message: 'Verification code sent to your email. Check your inbox!',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Verify email authentication code using Turnkey OTP
|
|
107
|
+
*/
|
|
108
|
+
export async function verifyEmailAuth(sessionId, code, turnkeyClient, sessionStorage) {
|
|
109
|
+
const storage = sessionStorage ?? getDefaultSessionStorage();
|
|
110
|
+
const session = storage.get(sessionId);
|
|
111
|
+
if (!session) {
|
|
112
|
+
throw new Error('Invalid or expired session');
|
|
113
|
+
}
|
|
114
|
+
// Check if session has expired
|
|
115
|
+
if (Date.now() - session.timestamp > SESSION_TIMEOUT) {
|
|
116
|
+
storage.delete(sessionId);
|
|
117
|
+
throw new Error('Session expired. Please request a new code.');
|
|
118
|
+
}
|
|
119
|
+
if (!session.otpId) {
|
|
120
|
+
throw new Error('OTP ID not found in session');
|
|
121
|
+
}
|
|
122
|
+
if (!session.subOrgId) {
|
|
123
|
+
throw new Error('Sub-organization ID not found');
|
|
124
|
+
}
|
|
125
|
+
console.log(`\n🔐 Verifying OTP for session ${sessionId}...`);
|
|
126
|
+
try {
|
|
127
|
+
// Verify the OTP code with Turnkey
|
|
128
|
+
const verifyResult = await turnkeyClient.apiClient().verifyOtp({
|
|
129
|
+
otpId: session.otpId,
|
|
130
|
+
otpCode: code,
|
|
131
|
+
expirationSeconds: '900', // 15 minutes
|
|
132
|
+
});
|
|
133
|
+
if (!verifyResult.verificationToken) {
|
|
134
|
+
throw new Error('OTP verification failed - no verification token returned');
|
|
135
|
+
}
|
|
136
|
+
console.log(`✅ OTP verified successfully!`);
|
|
137
|
+
// Mark session as verified
|
|
138
|
+
session.verified = true;
|
|
139
|
+
storage.set(sessionId, session);
|
|
140
|
+
return {
|
|
141
|
+
verified: true,
|
|
142
|
+
email: session.email,
|
|
143
|
+
subOrgId: session.subOrgId,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
console.error('❌ OTP verification failed:', error);
|
|
148
|
+
throw new Error(`Invalid verification code: ${error instanceof Error ? error.message : String(error)}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Check if a session is verified
|
|
153
|
+
*/
|
|
154
|
+
export function isSessionVerified(sessionId, sessionStorage) {
|
|
155
|
+
const storage = sessionStorage ?? getDefaultSessionStorage();
|
|
156
|
+
const session = storage.get(sessionId);
|
|
157
|
+
if (!session)
|
|
158
|
+
return false;
|
|
159
|
+
if (Date.now() - session.timestamp > SESSION_TIMEOUT) {
|
|
160
|
+
storage.delete(sessionId);
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
return session.verified;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Clean up a session after successful login
|
|
167
|
+
*/
|
|
168
|
+
export function cleanupSession(sessionId, sessionStorage) {
|
|
169
|
+
const storage = sessionStorage ?? getDefaultSessionStorage();
|
|
170
|
+
storage.delete(sessionId);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Get session data
|
|
174
|
+
*/
|
|
175
|
+
export function getSession(sessionId, sessionStorage) {
|
|
176
|
+
const storage = sessionStorage ?? getDefaultSessionStorage();
|
|
177
|
+
const session = storage.get(sessionId);
|
|
178
|
+
if (!session)
|
|
179
|
+
return undefined;
|
|
180
|
+
// Check if expired
|
|
181
|
+
if (Date.now() - session.timestamp > SESSION_TIMEOUT) {
|
|
182
|
+
storage.delete(sessionId);
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
return session;
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=email-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-auth.js","sourceRoot":"","sources":["../../src/server/email-auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side authentication utilities
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```typescript
|
|
6
|
+
* import {
|
|
7
|
+
* createAuthMiddleware,
|
|
8
|
+
* initiateEmailAuth,
|
|
9
|
+
* verifyEmailAuth,
|
|
10
|
+
* signToken,
|
|
11
|
+
* verifyToken,
|
|
12
|
+
* createTurnkeyClient,
|
|
13
|
+
* TurnkeyWebVHSigner
|
|
14
|
+
* } from '@originals/auth/server';
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export { createTurnkeyClient, getOrCreateTurnkeySubOrg } from './turnkey-client';
|
|
18
|
+
export { initiateEmailAuth, verifyEmailAuth, isSessionVerified, cleanupSession, getSession, type SessionStorage, createInMemorySessionStorage, } from './email-auth';
|
|
19
|
+
export { signToken, verifyToken, getAuthCookieConfig, getClearAuthCookieConfig, } from './jwt';
|
|
20
|
+
export { createAuthMiddleware } from './middleware';
|
|
21
|
+
export { TurnkeyWebVHSigner, createTurnkeySigner } from './turnkey-signer';
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AACjF,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,UAAU,EACV,KAAK,cAAc,EACnB,4BAA4B,GAC7B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,SAAS,EACT,WAAW,EACX,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side authentication utilities
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```typescript
|
|
6
|
+
* import {
|
|
7
|
+
* createAuthMiddleware,
|
|
8
|
+
* initiateEmailAuth,
|
|
9
|
+
* verifyEmailAuth,
|
|
10
|
+
* signToken,
|
|
11
|
+
* verifyToken,
|
|
12
|
+
* createTurnkeyClient,
|
|
13
|
+
* TurnkeyWebVHSigner
|
|
14
|
+
* } from '@originals/auth/server';
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export { createTurnkeyClient, getOrCreateTurnkeySubOrg } from './turnkey-client';
|
|
18
|
+
export { initiateEmailAuth, verifyEmailAuth, isSessionVerified, cleanupSession, getSession, createInMemorySessionStorage, } from './email-auth';
|
|
19
|
+
export { signToken, verifyToken, getAuthCookieConfig, getClearAuthCookieConfig, } from './jwt';
|
|
20
|
+
export { createAuthMiddleware } from './middleware';
|
|
21
|
+
export { TurnkeyWebVHSigner, createTurnkeySigner } from './turnkey-signer';
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AACjF,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,UAAU,EAEV,4BAA4B,GAC7B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,SAAS,EACT,WAAW,EACX,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWT Authentication Module
|
|
3
|
+
* Implements secure token issuance and validation with HTTP-only cookies
|
|
4
|
+
*/
|
|
5
|
+
import type { TokenPayload, AuthCookieConfig } from '../types';
|
|
6
|
+
/**
|
|
7
|
+
* Sign a JWT token for a user
|
|
8
|
+
* @param subOrgId - Turnkey sub-organization ID (stable identifier)
|
|
9
|
+
* @param email - User email (metadata)
|
|
10
|
+
* @param sessionToken - Optional Turnkey session token for user authentication
|
|
11
|
+
* @param options - Additional options
|
|
12
|
+
* @returns Signed JWT token string
|
|
13
|
+
*/
|
|
14
|
+
export declare function signToken(subOrgId: string, email: string, sessionToken?: string, options?: {
|
|
15
|
+
secret?: string;
|
|
16
|
+
expiresIn?: number;
|
|
17
|
+
issuer?: string;
|
|
18
|
+
audience?: string;
|
|
19
|
+
}): string;
|
|
20
|
+
/**
|
|
21
|
+
* Verify and decode a JWT token
|
|
22
|
+
* @param token - JWT token string
|
|
23
|
+
* @param options - Additional options
|
|
24
|
+
* @returns Decoded token payload
|
|
25
|
+
* @throws Error if token is invalid or expired
|
|
26
|
+
*/
|
|
27
|
+
export declare function verifyToken(token: string, options?: {
|
|
28
|
+
secret?: string;
|
|
29
|
+
issuer?: string;
|
|
30
|
+
audience?: string;
|
|
31
|
+
}): TokenPayload;
|
|
32
|
+
/**
|
|
33
|
+
* Generate a secure cookie configuration for authentication tokens
|
|
34
|
+
* @param token - JWT token to set in cookie
|
|
35
|
+
* @param options - Cookie options
|
|
36
|
+
* @returns Cookie configuration object
|
|
37
|
+
*/
|
|
38
|
+
export declare function getAuthCookieConfig(token: string, options?: {
|
|
39
|
+
cookieName?: string;
|
|
40
|
+
maxAge?: number;
|
|
41
|
+
secure?: boolean;
|
|
42
|
+
}): AuthCookieConfig;
|
|
43
|
+
/**
|
|
44
|
+
* Get cookie configuration for logout (clears the auth cookie)
|
|
45
|
+
* @param cookieName - Name of the cookie to clear
|
|
46
|
+
* @returns Cookie configuration for clearing
|
|
47
|
+
*/
|
|
48
|
+
export declare function getClearAuthCookieConfig(cookieName?: string): AuthCookieConfig;
|
|
49
|
+
//# sourceMappingURL=jwt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/server/jwt.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAgB/D;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACA,MAAM,CAuBR;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACA,YAAY,CAuBd;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IACR,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GACA,gBAAgB,CAclB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAc9E"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWT Authentication Module
|
|
3
|
+
* Implements secure token issuance and validation with HTTP-only cookies
|
|
4
|
+
*/
|
|
5
|
+
import jwt from 'jsonwebtoken';
|
|
6
|
+
// 7 days in seconds
|
|
7
|
+
const DEFAULT_JWT_EXPIRES_IN = 7 * 24 * 60 * 60;
|
|
8
|
+
/**
|
|
9
|
+
* Get JWT secret from config or environment
|
|
10
|
+
*/
|
|
11
|
+
function getJwtSecret(configSecret) {
|
|
12
|
+
const secret = configSecret ?? process.env.JWT_SECRET;
|
|
13
|
+
if (!secret) {
|
|
14
|
+
throw new Error('JWT_SECRET environment variable is required');
|
|
15
|
+
}
|
|
16
|
+
return secret;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Sign a JWT token for a user
|
|
20
|
+
* @param subOrgId - Turnkey sub-organization ID (stable identifier)
|
|
21
|
+
* @param email - User email (metadata)
|
|
22
|
+
* @param sessionToken - Optional Turnkey session token for user authentication
|
|
23
|
+
* @param options - Additional options
|
|
24
|
+
* @returns Signed JWT token string
|
|
25
|
+
*/
|
|
26
|
+
export function signToken(subOrgId, email, sessionToken, options) {
|
|
27
|
+
if (!subOrgId) {
|
|
28
|
+
throw new Error('Sub-organization ID is required for token signing');
|
|
29
|
+
}
|
|
30
|
+
const secret = getJwtSecret(options?.secret);
|
|
31
|
+
const payload = {
|
|
32
|
+
sub: subOrgId,
|
|
33
|
+
email,
|
|
34
|
+
};
|
|
35
|
+
if (sessionToken) {
|
|
36
|
+
payload.sessionToken = sessionToken;
|
|
37
|
+
}
|
|
38
|
+
const signOptions = {
|
|
39
|
+
expiresIn: options?.expiresIn ?? DEFAULT_JWT_EXPIRES_IN,
|
|
40
|
+
issuer: options?.issuer ?? 'originals-auth',
|
|
41
|
+
audience: options?.audience ?? 'originals-api',
|
|
42
|
+
};
|
|
43
|
+
return jwt.sign(payload, secret, signOptions);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Verify and decode a JWT token
|
|
47
|
+
* @param token - JWT token string
|
|
48
|
+
* @param options - Additional options
|
|
49
|
+
* @returns Decoded token payload
|
|
50
|
+
* @throws Error if token is invalid or expired
|
|
51
|
+
*/
|
|
52
|
+
export function verifyToken(token, options) {
|
|
53
|
+
const secret = getJwtSecret(options?.secret);
|
|
54
|
+
try {
|
|
55
|
+
const payload = jwt.verify(token, secret, {
|
|
56
|
+
issuer: options?.issuer ?? 'originals-auth',
|
|
57
|
+
audience: options?.audience ?? 'originals-api',
|
|
58
|
+
});
|
|
59
|
+
if (!payload.sub) {
|
|
60
|
+
throw new Error('Token missing sub-organization ID');
|
|
61
|
+
}
|
|
62
|
+
return payload;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error instanceof jwt.TokenExpiredError) {
|
|
66
|
+
throw new Error('Token has expired');
|
|
67
|
+
}
|
|
68
|
+
if (error instanceof jwt.JsonWebTokenError) {
|
|
69
|
+
throw new Error('Invalid token');
|
|
70
|
+
}
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Generate a secure cookie configuration for authentication tokens
|
|
76
|
+
* @param token - JWT token to set in cookie
|
|
77
|
+
* @param options - Cookie options
|
|
78
|
+
* @returns Cookie configuration object
|
|
79
|
+
*/
|
|
80
|
+
export function getAuthCookieConfig(token, options) {
|
|
81
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
82
|
+
return {
|
|
83
|
+
name: options?.cookieName ?? 'auth_token',
|
|
84
|
+
value: token,
|
|
85
|
+
options: {
|
|
86
|
+
httpOnly: true, // Cannot be accessed by JavaScript (XSS protection)
|
|
87
|
+
secure: options?.secure ?? isProduction, // HTTPS only in production
|
|
88
|
+
sameSite: 'strict', // CSRF protection
|
|
89
|
+
maxAge: options?.maxAge ?? 7 * 24 * 60 * 60 * 1000, // 7 days in milliseconds
|
|
90
|
+
path: '/', // Available for all routes
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get cookie configuration for logout (clears the auth cookie)
|
|
96
|
+
* @param cookieName - Name of the cookie to clear
|
|
97
|
+
* @returns Cookie configuration for clearing
|
|
98
|
+
*/
|
|
99
|
+
export function getClearAuthCookieConfig(cookieName) {
|
|
100
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
101
|
+
return {
|
|
102
|
+
name: cookieName ?? 'auth_token',
|
|
103
|
+
value: '',
|
|
104
|
+
options: {
|
|
105
|
+
httpOnly: true,
|
|
106
|
+
secure: isProduction,
|
|
107
|
+
sameSite: 'strict',
|
|
108
|
+
maxAge: 0, // Expire immediately
|
|
109
|
+
path: '/',
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=jwt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../src/server/jwt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express authentication middleware factory
|
|
3
|
+
*/
|
|
4
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
5
|
+
import type { AuthMiddlewareOptions } from '../types';
|
|
6
|
+
/**
|
|
7
|
+
* Create an authentication middleware for Express
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { createAuthMiddleware } from '@originals/auth/server';
|
|
12
|
+
*
|
|
13
|
+
* const authenticateUser = createAuthMiddleware({
|
|
14
|
+
* getUserByTurnkeyId: async (turnkeyId) => {
|
|
15
|
+
* return db.query.users.findFirst({
|
|
16
|
+
* where: eq(users.turnkeySubOrgId, turnkeyId)
|
|
17
|
+
* });
|
|
18
|
+
* },
|
|
19
|
+
* createUser: async (turnkeyId, email, temporaryDid) => {
|
|
20
|
+
* return db.insert(users).values({
|
|
21
|
+
* turnkeySubOrgId: turnkeyId,
|
|
22
|
+
* email,
|
|
23
|
+
* did: temporaryDid,
|
|
24
|
+
* }).returning().then(rows => rows[0]);
|
|
25
|
+
* }
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* app.get('/api/protected', authenticateUser, (req, res) => {
|
|
29
|
+
* res.json({ user: req.user });
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function createAuthMiddleware(options: AuthMiddlewareOptions): (req: Request, res: Response, next: NextFunction) => Promise<void | Response>;
|
|
34
|
+
/**
|
|
35
|
+
* Optional authentication middleware - doesn't fail if not authenticated
|
|
36
|
+
* Attaches user to request if valid token exists, otherwise continues without user
|
|
37
|
+
*/
|
|
38
|
+
export declare function createOptionalAuthMiddleware(options: AuthMiddlewareOptions): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
39
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/server/middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE/D,OAAO,KAAK,EAAE,qBAAqB,EAAkC,MAAM,UAAU,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,qBAAqB,GAC7B,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,GAAG,QAAQ,CAAC,CAqD/E;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,qBAAqB,GAC7B,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAkCpE"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express authentication middleware factory
|
|
3
|
+
*/
|
|
4
|
+
import { verifyToken } from './jwt';
|
|
5
|
+
/**
|
|
6
|
+
* Create an authentication middleware for Express
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { createAuthMiddleware } from '@originals/auth/server';
|
|
11
|
+
*
|
|
12
|
+
* const authenticateUser = createAuthMiddleware({
|
|
13
|
+
* getUserByTurnkeyId: async (turnkeyId) => {
|
|
14
|
+
* return db.query.users.findFirst({
|
|
15
|
+
* where: eq(users.turnkeySubOrgId, turnkeyId)
|
|
16
|
+
* });
|
|
17
|
+
* },
|
|
18
|
+
* createUser: async (turnkeyId, email, temporaryDid) => {
|
|
19
|
+
* return db.insert(users).values({
|
|
20
|
+
* turnkeySubOrgId: turnkeyId,
|
|
21
|
+
* email,
|
|
22
|
+
* did: temporaryDid,
|
|
23
|
+
* }).returning().then(rows => rows[0]);
|
|
24
|
+
* }
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* app.get('/api/protected', authenticateUser, (req, res) => {
|
|
28
|
+
* res.json({ user: req.user });
|
|
29
|
+
* });
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function createAuthMiddleware(options) {
|
|
33
|
+
const cookieName = options.cookieName ?? 'auth_token';
|
|
34
|
+
return async (req, res, next) => {
|
|
35
|
+
try {
|
|
36
|
+
// Get JWT token from HTTP-only cookie
|
|
37
|
+
const token = req.cookies?.[cookieName];
|
|
38
|
+
if (!token) {
|
|
39
|
+
return res.status(401).json({ error: 'Not authenticated' });
|
|
40
|
+
}
|
|
41
|
+
// Verify JWT token
|
|
42
|
+
const payload = verifyToken(token, { secret: options.jwtSecret });
|
|
43
|
+
const turnkeySubOrgId = payload.sub;
|
|
44
|
+
const email = payload.email;
|
|
45
|
+
// Check if user already exists
|
|
46
|
+
let user = await options.getUserByTurnkeyId(turnkeySubOrgId);
|
|
47
|
+
// If user doesn't exist and createUser is provided, create user
|
|
48
|
+
if (!user && options.createUser) {
|
|
49
|
+
console.log(`Creating user record for ${email}...`);
|
|
50
|
+
// Use temporary DID as placeholder until user creates real DID
|
|
51
|
+
const temporaryDid = `temp:turnkey:${turnkeySubOrgId}`;
|
|
52
|
+
user = await options.createUser(turnkeySubOrgId, email, temporaryDid);
|
|
53
|
+
console.log(`✅ User created: ${email}`);
|
|
54
|
+
console.log(` Turnkey sub-org ID: ${turnkeySubOrgId}`);
|
|
55
|
+
console.log(` Temporary DID: ${temporaryDid}`);
|
|
56
|
+
}
|
|
57
|
+
if (!user) {
|
|
58
|
+
return res.status(401).json({ error: 'User not found' });
|
|
59
|
+
}
|
|
60
|
+
// Add user info to request
|
|
61
|
+
req.user = {
|
|
62
|
+
id: user.id,
|
|
63
|
+
turnkeySubOrgId,
|
|
64
|
+
email,
|
|
65
|
+
did: user.did,
|
|
66
|
+
sessionToken: payload.sessionToken,
|
|
67
|
+
};
|
|
68
|
+
next();
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
console.error('Authentication error:', error);
|
|
72
|
+
return res.status(401).json({ error: 'Invalid or expired token' });
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Optional authentication middleware - doesn't fail if not authenticated
|
|
78
|
+
* Attaches user to request if valid token exists, otherwise continues without user
|
|
79
|
+
*/
|
|
80
|
+
export function createOptionalAuthMiddleware(options) {
|
|
81
|
+
const cookieName = options.cookieName ?? 'auth_token';
|
|
82
|
+
return async (req, res, next) => {
|
|
83
|
+
try {
|
|
84
|
+
const token = req.cookies?.[cookieName];
|
|
85
|
+
if (!token) {
|
|
86
|
+
next();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const payload = verifyToken(token, { secret: options.jwtSecret });
|
|
90
|
+
const turnkeySubOrgId = payload.sub;
|
|
91
|
+
const email = payload.email;
|
|
92
|
+
const user = await options.getUserByTurnkeyId(turnkeySubOrgId);
|
|
93
|
+
if (user) {
|
|
94
|
+
req.user = {
|
|
95
|
+
id: user.id,
|
|
96
|
+
turnkeySubOrgId,
|
|
97
|
+
email,
|
|
98
|
+
did: user.did,
|
|
99
|
+
sessionToken: payload.sessionToken,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
next();
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Token invalid or expired, continue without user
|
|
106
|
+
next();
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/server/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side Turnkey client utilities
|
|
3
|
+
*/
|
|
4
|
+
import { Turnkey } from '@turnkey/sdk-server';
|
|
5
|
+
export interface TurnkeyClientConfig {
|
|
6
|
+
/** Turnkey API base URL (default: https://api.turnkey.com) */
|
|
7
|
+
apiBaseUrl?: string;
|
|
8
|
+
/** Turnkey API public key */
|
|
9
|
+
apiPublicKey: string;
|
|
10
|
+
/** Turnkey API private key */
|
|
11
|
+
apiPrivateKey: string;
|
|
12
|
+
/** Default organization ID */
|
|
13
|
+
organizationId: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create a Turnkey server client
|
|
17
|
+
*/
|
|
18
|
+
export declare function createTurnkeyClient(config?: Partial<TurnkeyClientConfig>): Turnkey;
|
|
19
|
+
/**
|
|
20
|
+
* Get or create a Turnkey sub-organization for a user
|
|
21
|
+
* Creates sub-org with email-only root user and required wallet accounts
|
|
22
|
+
*/
|
|
23
|
+
export declare function getOrCreateTurnkeySubOrg(email: string, turnkeyClient: Turnkey): Promise<string>;
|
|
24
|
+
//# sourceMappingURL=turnkey-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turnkey-client.d.ts","sourceRoot":"","sources":["../../src/server/turnkey-client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE9C,MAAM,WAAW,mBAAmB;IAClC,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,8BAA8B;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,8BAA8B;IAC9B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAqBlF;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,OAAO,GACrB,OAAO,CAAC,MAAM,CAAC,CAkGjB"}
|