Skip to content

Commit a95e774

Browse files
committed
feat: custom auth works
1 parent 94ed988 commit a95e774

File tree

36 files changed

+1357
-959
lines changed

36 files changed

+1357
-959
lines changed

packages/auth-services/src/auth-server/src/createAuthServer.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@ import { mainAppQueue } from '../../queue-manager/src/bullmqSetup'; // Adjusted
1010
import { apiKeyGateAndTracking } from '../middleware/apiKeyGate'; // Adjusted path
1111
import { rateLimiter } from '../middleware/rateLimiter'; // Adjusted path
1212
import { resp } from './response-helpers/response-helpers'; // Adjusted path
13-
import {
14-
customAuthLoginRoute,
15-
customAuthVerifyTokenRoute,
16-
} from './routes/auth/custom-auth-routes';
13+
1714
import { stytchEmailRoutes } from './routes/auth/stytch/stytch-email';
1815
import { stytchWhatsAppRoutes } from './routes/auth/stytch/stytch-otp';
1916
import { stytchSmsRoutes } from './routes/auth/stytch/stytch-sms';
@@ -129,10 +126,6 @@ export const createLitAuthServer = (
129126
stytchWhatsAppRoutes(groupApp);
130127
stytchTotpRoutes(groupApp);
131128

132-
// Custom Auth
133-
customAuthLoginRoute(groupApp);
134-
customAuthVerifyTokenRoute(groupApp);
135-
136129
return groupApp;
137130
})
138131

packages/auth-services/src/auth-server/src/response-helpers/response-helpers.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,18 @@ const _res200 = (data: any) => {
3333
status: 200,
3434
});
3535
};
36+
37+
const _res401 = (error: string) => {
38+
return new Response(BigIntStringify({ error }), {
39+
headers: HEADERS,
40+
status: 401,
41+
});
42+
};
43+
3644
export const resp: Record<string, (...args: any[]) => Response> = {
3745
SUCCESS: _res200,
3846
QUEUED: _res202,
3947
ERROR: _res500,
4048
BAD_REQUEST: _res400,
49+
UNAUTHORIZED: _res401,
4150
};
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { MintRequestRaw } from '@lit-protocol/networks/src/networks/vNaga/LitChainClient/schemas/MintRequestSchema';
2+
import { ElysiaInstance } from '../../types/ElysiaInstance.type';
3+
import { addJob } from '../../../../queue-manager/src/bullmqSetup';
4+
import { resp } from '../../response-helpers/response-helpers';
5+
import { mintPkpDoc } from '../../../../queue-manager/src/handlers/pkpMint/pkpMint.doc';
6+
7+
export const mint = (app: ElysiaInstance) => {
8+
app.post(
9+
'/mint',
10+
async ({ body }: { body: MintRequestRaw }) => {
11+
try {
12+
const job = await addJob('pkpMint', { requestBody: body });
13+
return resp.QUEUED(job.id, 'PKP minting request queued successfully.');
14+
} catch (error: any) {
15+
console.error(`[API] Failed to add job 'pkpMint' to queue:`, error);
16+
return resp.ERROR(
17+
'Failed to queue PKP minting request.' + error.message
18+
);
19+
}
20+
},
21+
mintPkpDoc
22+
);
23+
return app;
24+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Job Status routes
3+
* Handles status checking for queued jobs
4+
*/
5+
import { getJobStatus } from '../../../queue-manager/src/bullmqSetup'; // Adjusted path
6+
import { getStatusDoc } from '../../../queue-manager/src/handlers/status/getStatus.doc'; // Adjusted path
7+
import { resp } from '../response-helpers/response-helpers';
8+
import { ElysiaInstance } from '../types/ElysiaInstance.type';
9+
10+
export const statusRoutes = (app: ElysiaInstance): ElysiaInstance => {
11+
// =============================================================
12+
// Get Job Status (/status/:jobId)
13+
// =============================================================
14+
app.get(
15+
'/status/:jobId',
16+
async ({ params }: { params: { jobId: string } }) => {
17+
const { jobId } = params;
18+
if (!jobId) {
19+
return resp.BAD_REQUEST('Job ID is required.');
20+
}
21+
try {
22+
const responsePayload = await getJobStatus(jobId);
23+
return resp.SUCCESS(responsePayload);
24+
} catch (error: any) {
25+
console.error(`[API] Failed to get status for job ${jobId}:`, error);
26+
return resp.ERROR('Failed to retrieve job status.' + error.message);
27+
}
28+
},
29+
getStatusDoc
30+
);
31+
32+
return app;
33+
};

packages/auth/src/index.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import * as authenticators from './lib/authenticators';
44
import { WebAuthnAuthenticator } from './lib/authenticators';
55
import { DiscordAuthenticator } from './lib/authenticators/native/DiscordAuthenticator';
66
import { GoogleAuthenticator } from './lib/authenticators/native/GoogleAuthenticator';
7+
import { StytchEmailOtpAuthenticator } from './lib/authenticators/stytch/factors/StytchEmailOtpAuthenticator';
8+
import { StytchSmsOtpAuthenticator } from './lib/authenticators/stytch/factors/StytchSmsOtpAuthenticator';
9+
import { StytchTotp2FAAuthenticator } from './lib/authenticators/stytch/factors/2fa/StytchTotp2FAAuthenticator';
10+
11+
import { StytchWhatsAppOtpAuthenticator } from './lib/authenticators/stytch/factors/StytchWhatsAppOtpAuthenticator';
712
import { ViemAccountAuthenticator } from './lib/authenticators/ViemAccountAuthenticator';
813
import { WalletClientAuthenticator } from './lib/authenticators/WalletClientAuthenticator';
914
// import { GetAuthContext } from './lib/AuthManager/getAuthContext';
@@ -22,7 +27,7 @@ export type { LitAuthStorageProvider };
2227
/**
2328
* Type definition for the structure of authentication data used within the Lit Auth client.
2429
*/
25-
export type { LitAuthData };
30+
export type { LitAuthData };
2631

2732
/**
2833
* Type definition for the structure of authentication context used within the Lit Auth client.
@@ -61,8 +66,8 @@ export { authenticators };
6166
*/
6267
// export { createAuthManager } from './lib/auth-manager';
6368
// export { getAuthContext } from './lib/AuthManager/getAuthContext';
64-
export { getEoaAuthContext } from './lib/AuthManager/authContexts/getEoaAuthContext';
65-
export { getPkpAuthContext } from './lib/AuthManager/authContexts/getPkpAuthContext';
69+
export { getEoaAuthContext } from './lib/AuthManager/authContexts/getEoaAuthContext';
70+
export { getPkpAuthContext } from './lib/AuthManager/authContexts/getPkpAuthContext';
6671
/**
6772
* Class responsible for communicating with the Lit Relay server.
6873
* Used for operations like minting PKPs associated with authentication methods.
@@ -91,6 +96,11 @@ export {
9196
GoogleAuthenticator,
9297
ViemAccountAuthenticator,
9398
WalletClientAuthenticator,
94-
WebAuthnAuthenticator
99+
WebAuthnAuthenticator,
100+
StytchEmailOtpAuthenticator,
101+
StytchSmsOtpAuthenticator,
102+
StytchTotp2FAAuthenticator,
103+
StytchWhatsAppOtpAuthenticator,
95104
};
96105

106+
export { ExampleAppAuthenticator } from './lib/authenticators/custom/ExampleAppAuthenticator';

packages/auth/src/lib/AuthManager/auth-manager.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import { getChildLogger } from '@lit-protocol/logger';
2-
import {
3-
AuthData,
4-
HexPrefixedSchema
5-
} from '@lit-protocol/schemas';
2+
import { AuthData, HexPrefixedSchema } from '@lit-protocol/schemas';
63
import { z } from 'zod';
74
import { AuthConfigV2 } from '../authenticators/types';
85
import type { LitAuthStorageProvider } from '../storage/types';
@@ -12,6 +9,9 @@ import {
129
} from './authAdapters/getEoaAuthContextAdapter';
1310
import { getPkpAuthContextAdapter } from './authAdapters/getPkpAuthContextAdapter';
1411
import { AuthConfigSchema } from './authContexts/BaseAuthContextType';
12+
import { getCustomAuthContextAdapter } from './authAdapters/getCustomAuthContextAdapter';
13+
import { hexToBigInt, keccak256, toBytes } from 'viem';
14+
1515
export interface AuthManagerParams {
1616
storage: LitAuthStorageProvider;
1717
}
@@ -76,14 +76,26 @@ export const createAuthManager = (authManagerParams: AuthManagerParams) => {
7676
}) => {
7777
return getPkpAuthContextAdapter(authManagerParams, params);
7878
},
79-
// createCustomAuthContext: <T extends ICustomAuthenticator>(params: {
80-
// authenticator: T;
81-
// settings: ConstructorParameters<T>[0]; // Infer settings type from constructor
82-
// config: { pkpPublicKey: string; [key: string]: any }; // Execution config
83-
// authConfig: AuthConfigV2;
84-
// litClient: BaseAuthContext<any>['litClient'];
85-
// }) => {
86-
// return getCustomAuthContextAdapter(authManagerParams, params);
87-
// },
79+
createCustomAuthContext: (params: {
80+
// authData: AuthData;
81+
pkpPublicKey: z.infer<typeof HexPrefixedSchema>;
82+
authConfig: AuthConfigV2;
83+
litClient: BaseAuthContext<any>['litClient'];
84+
85+
// custom auth params
86+
customAuthParams: {
87+
litActionCode?: string;
88+
litActionIpfsId?: string;
89+
jsParams?: Record<string, any>;
90+
};
91+
}) => {
92+
// make jsParams nested inside jsParams so that
93+
// the dev can check all variables inside an object in Lit action
94+
params.customAuthParams.jsParams = {
95+
jsParams: params.customAuthParams.jsParams,
96+
};
97+
98+
return getCustomAuthContextAdapter(authManagerParams, params);
99+
},
88100
};
89101
};
Lines changed: 86 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,107 @@
1-
import { ethers } from 'ethers';
1+
import { AUTH_METHOD_TYPE_VALUES, PRODUCT_IDS } from '@lit-protocol/constants';
22
import {
3-
AuthConfig,
4-
AuthManagerParams,
5-
BaseAuthContext,
6-
} from '../auth-manager';
7-
import { PkpAuthDepsSchema } from './getPkpAuthContextAdapter';
8-
import { AUTH_METHOD_TYPE } from '@lit-protocol/constants';
3+
AuthData,
4+
HexPrefixedSchema,
5+
NodeUrlsSchema,
6+
} from '@lit-protocol/schemas';
7+
import { ethers } from 'ethers';
8+
import { z } from 'zod';
9+
import { AuthConfigV2 } from '../../authenticators/types';
10+
import { AuthManagerParams } from '../auth-manager';
11+
import { getCustomAuthContext } from '../authContexts/getCustomAuthContext';
12+
import { processResources } from '../utils/processResources';
913
import { tryGetCachedAuthData } from '../try-getters/tryGetCachedAuthData';
1014

11-
export interface ICustomAuthenticator {
12-
new (settings: any): ICustomAuthenticatorInstance;
13-
LIT_ACTION_CODE_BASE64?: string;
14-
LIT_ACTION_IPFS_ID?: string;
15-
}
16-
17-
interface ICustomAuthenticatorInstance {
18-
// Method to perform external auth and return jsParams for the Lit Action
19-
// Accepts the config object which includes pkpPublicKey and other needed params
20-
authenticate(config: {
21-
pkpPublicKey: string;
22-
[key: string]: any;
23-
}): Promise<Record<string, any> | null>;
24-
}
15+
export const CustomAuthDepsSchema = z.object({
16+
nonce: z.any(),
17+
currentEpoch: z.any(),
18+
getSignSessionKey: z.any(),
19+
nodeUrls: NodeUrlsSchema,
20+
});
2521

2622
export async function getCustomAuthContextAdapter(
2723
upstreamParams: AuthManagerParams,
2824
params: {
29-
authenticator: ICustomAuthenticator; // Use the interface type
30-
settings: Record<string, any>; // For constructor
31-
config: { pkpPublicKey: string; [key: string]: any }; // For authenticate method
32-
authConfig: AuthConfig; // For SIWE/session
33-
litClient: BaseAuthContext<any>['litClient'];
25+
// authData: AuthData;
26+
pkpPublicKey: z.infer<typeof HexPrefixedSchema>;
27+
authConfig: AuthConfigV2;
28+
litClient: {
29+
getContext: () => Promise<any>;
30+
};
31+
customAuthParams: {
32+
litActionCode?: string;
33+
litActionIpfsId?: string;
34+
jsParams?: Record<string, any>;
35+
};
3436
}
3537
) {
36-
// 1. Instantiate the custom authenticator helper using 'settings'
37-
const customAuthHelper = new params.authenticator(params.settings);
38+
const _resources = processResources(params.authConfig.resources);
3839

39-
// 2. Call the helper's authenticate method using 'config'
40-
if (!customAuthHelper.authenticate) {
41-
throw new Error("Custom authenticator is missing 'authenticate' method.");
42-
}
43-
// Pass the entire config object to the authenticator's authenticate method
44-
const jsParams = await customAuthHelper.authenticate(params.config);
45-
if (!jsParams) {
46-
throw new Error('Custom authenticator failed to produce jsParams.');
47-
}
40+
// TODO: 👇 The plan is to identify if the certain operations could be wrapped inside a single function
41+
// where different network modules can provide their own implementations.
4842

49-
// 3. Get the static Lit Action code/ID from the authenticator class
50-
const litActionCode = params.authenticator.LIT_ACTION_CODE_BASE64;
51-
const litActionIpfsId = params.authenticator.LIT_ACTION_IPFS_ID; // Optional
52-
if (!litActionCode && !litActionIpfsId) {
53-
throw new Error(
54-
'Custom authenticator is missing static LIT_ACTION_CODE_BASE64 or LIT_ACTION_IPFS_ID.'
55-
);
56-
}
43+
// TODO: ❗️THIS IS NOT TYPED - we have to fix this!
44+
const litClientCtx = await params.litClient.getContext();
45+
46+
// TODO: ❗️THIS IS NOT TYPED - we have to fix this! (This can be in both Naga and Datil)
47+
const latestConnectionInfo = litClientCtx.latestConnectionInfo;
5748

58-
// 4. Extract pkpPublicKey (already available in params.config)
59-
const pkpPublicKey = params.config.pkpPublicKey;
49+
// TODO: ❗️THIS IS NOT TYPED - we have to fix this! (This can only be in Naga)
50+
const nodePrices = latestConnectionInfo.priceFeedInfo.networkPrices;
6051

61-
// 5. Get node dependencies, session key etc.
62-
const litClientConfig = PkpAuthDepsSchema.parse({
63-
nonce: await params.litClient.getLatestBlockhash(),
64-
currentEpoch: await params.litClient.getCurrentEpoch(),
65-
getSignSessionKey: params.litClient.getSignSessionKey,
66-
nodeUrls: await params.litClient.getMaxPricesForNodeProduct({
67-
product: 'LIT_ACTION', // Or appropriate product
52+
// TODO: ❗️THIS IS NOT TYPED - we have to fix this! (This can be in both Naga and Datil)
53+
const handshakeResult = litClientCtx.handshakeResult;
54+
55+
// TODO: ❗️THIS IS NOT TYPED - we have to fix this! (This can be in both Naga and Datil)
56+
const threshold = handshakeResult.threshold;
57+
58+
// TODO: ❗️THIS IS NOT TYPED - we have to fix this! (This can only be in Naga)
59+
const nodeUrls = litClientCtx.getMaxPricesForNodeProduct({
60+
nodePrices: nodePrices,
61+
userMaxPrice: litClientCtx.getUserMaxPrice({
62+
product: 'LIT_ACTION',
6863
}),
64+
productId: PRODUCT_IDS['LIT_ACTION'],
65+
numRequiredNodes: threshold,
6966
});
70-
const pkpAddress = ethers.utils.computeAddress(pkpPublicKey);
71-
const authData = await tryGetCachedAuthData({
67+
68+
const pkpAddress = ethers.utils.computeAddress(params.pkpPublicKey);
69+
70+
const litAuthData = await tryGetCachedAuthData({
7271
storage: upstreamParams.storage,
7372
address: pkpAddress,
74-
expiration: params.authConfig.expiration,
75-
type: AUTH_METHOD_TYPE.LitAction, // Session type remains LitAction
73+
expiration: params.authConfig.expiration!,
74+
type: 'custom' as unknown as AUTH_METHOD_TYPE_VALUES,
7675
});
7776

78-
// 6. Prepare the request body for the node signing function
79-
const requestBodyForCustomAuth = {
80-
sessionKey: authData.sessionKey.keyPair.publicKey,
81-
pkpPublicKey: pkpPublicKey,
82-
statement: params.authConfig.statement,
83-
domain: params.authConfig.domain,
84-
expiration: params.authConfig.expiration,
85-
resources: params.authConfig.resources,
86-
uri: authData.sessionKey.keyPair.publicKey,
87-
nonce: litClientConfig.nonce,
88-
...(litActionCode && { code: litActionCode }),
89-
...(litActionIpfsId && { litActionIpfsId: litActionIpfsId }),
90-
jsParams: jsParams, // Use the result from customAuthHelper.authenticate
91-
authMethods: [],
92-
epoch: litClientConfig.currentEpoch,
93-
// ... other fields like curveType, signingScheme ...
94-
};
95-
96-
// 7. Return the auth context object
97-
return {
98-
chain: 'ethereum',
99-
pkpPublicKey: pkpPublicKey,
100-
resources: params.authConfig.resources,
101-
capabilityAuthSigs: params.authConfig.capabilityAuthSigs,
102-
expiration: params.authConfig.expiration,
103-
authNeededCallback: async () => {
104-
const authSig = await litClientConfig.getSignSessionKey({
105-
requestBody: requestBodyForCustomAuth,
106-
nodeUrls: litClientConfig.nodeUrls.map((node: any) => node.url),
107-
});
108-
return authSig;
77+
return getCustomAuthContext({
78+
authentication: {
79+
pkpPublicKey: params.pkpPublicKey,
80+
// authData: {} as any,
10981
},
110-
};
82+
authConfig: {
83+
domain: params.authConfig.domain!,
84+
resources: _resources,
85+
capabilityAuthSigs: params.authConfig.capabilityAuthSigs!,
86+
expiration: params.authConfig.expiration!,
87+
statement: params.authConfig.statement!,
88+
},
89+
customParams: {
90+
litActionCode: params.customAuthParams.litActionCode,
91+
litActionIpfsId: params.customAuthParams.litActionIpfsId,
92+
jsParams: params.customAuthParams.jsParams,
93+
},
94+
deps: {
95+
litAuthData: litAuthData,
96+
connection: {
97+
nonce: litClientCtx.latestBlockhash,
98+
currentEpoch:
99+
litClientCtx.latestConnectionInfo.epochState.currentNumber,
100+
nodeUrls: nodeUrls,
101+
},
102+
signCustomSessionKey: litClientCtx.signCustomSessionKey,
103+
storage: upstreamParams.storage,
104+
pkpAddress: pkpAddress,
105+
},
106+
});
111107
}

0 commit comments

Comments
 (0)