@payez/next-mvp 3.0.0 → 3.1.1

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.
@@ -1,223 +1,223 @@
1
- "use strict";
2
- /**
3
- * Credentials Provider
4
- *
5
- * Handles email/password authentication via PayEz IDP.
6
- * Creates Redis session and returns minimal user object to NextAuth.
7
- *
8
- * FLOW:
9
- * 1. User submits email/password
10
- * 2. We call IDP /api/ExternalAuth/login
11
- * 3. IDP returns tokens if credentials valid
12
- * 4. We create Redis session with tokens
13
- * 5. Return user object with redisSessionId to NextAuth
14
- *
15
- * @version 1.0.0
16
- * @since auth-refactor-2026-01
17
- */
18
- var __importDefault = (this && this.__importDefault) || function (mod) {
19
- return (mod && mod.__esModule) ? mod : { "default": mod };
20
- };
21
- Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.createCredentialsProvider = createCredentialsProvider;
23
- const credentials_1 = __importDefault(require("next-auth/providers/credentials"));
24
- const session_store_1 = require("../../lib/session-store");
25
- const idp_client_1 = require("../utils/idp-client");
26
- const token_utils_1 = require("../utils/token-utils");
27
- const auth_types_1 = require("../types/auth-types");
28
- // NOTE: Using any for sessionData until Phase 3 normalizes types
29
- // ============================================================================
30
- // CREDENTIALS PROVIDER
31
- // ============================================================================
32
- /**
33
- * Create the CredentialsProvider for NextAuth.
34
- *
35
- * This provider handles email/password login. The authorize function
36
- * is called when a user submits the login form.
37
- */
38
- function createCredentialsProvider() {
39
- return (0, credentials_1.default)({
40
- id: 'credentials',
41
- name: 'Credentials',
42
- credentials: {
43
- email: { label: 'Email', type: 'email' },
44
- password: { label: 'Password', type: 'password' },
45
- },
46
- authorize: authorizeCredentials,
47
- });
48
- }
49
- /**
50
- * Authorize user with email/password.
51
- *
52
- * This is the core authentication function. It:
53
- * 1. Validates credentials with IDP
54
- * 2. Decodes the returned tokens
55
- * 3. Creates a Redis session
56
- * 4. Returns user info for NextAuth JWT
57
- *
58
- * @param credentials - Email and password from login form
59
- * @param req - The incoming request (for IP/UA forwarding)
60
- * @returns User object for NextAuth, or null/throws on failure
61
- */
62
- async function authorizeCredentials(credentials, req) {
63
- // -------------------------------------------------------------------------
64
- // Validate Input
65
- // -------------------------------------------------------------------------
66
- if (!credentials?.email || !credentials?.password) {
67
- throw new Error('Email and password required');
68
- }
69
- const loginCredentials = {
70
- email: credentials.email,
71
- password: credentials.password,
72
- };
73
- // Extract client info for audit logging
74
- const clientHeaders = extractClientHeaders(req);
75
- // -------------------------------------------------------------------------
76
- // Call IDP
77
- // -------------------------------------------------------------------------
78
- const loginResult = await (0, idp_client_1.idpLogin)(loginCredentials, clientHeaders);
79
- if (!loginResult.success || !loginResult.result) {
80
- // Build structured error for frontend
81
- const errorResponse = buildAuthError(loginResult.error);
82
- throw new Error(JSON.stringify(errorResponse));
83
- }
84
- const { access_token, refresh_token, user: idpUser } = loginResult.result;
85
- // -------------------------------------------------------------------------
86
- // Decode Token
87
- // -------------------------------------------------------------------------
88
- const decoded = (0, token_utils_1.decodeIdpAccessToken)(access_token);
89
- if (!decoded) {
90
- throw new Error('Failed to decode token');
91
- }
92
- // Extract kid from JWT header (CRITICAL: this is different from client_id in payload)
93
- const bearerKeyId = (0, token_utils_1.extractKidFromToken)(access_token);
94
- if (bearerKeyId) {
95
- console.log('[CREDENTIALS] Extracted bearerKeyId (kid) from JWT header:', bearerKeyId);
96
- }
97
- else {
98
- console.warn('[CREDENTIALS] No kid found in JWT header - token may be unsigned or malformed');
99
- }
100
- // Extract claims from token
101
- const email = (0, token_utils_1.extractEmailFromToken)(decoded);
102
- const roles = (0, token_utils_1.extractRolesFromToken)(decoded);
103
- const amrClaims = (0, token_utils_1.extractAmrFromToken)(decoded);
104
- const acrLevel = decoded.acr || '1';
105
- const userId = decoded.sub;
106
- // Check if 2FA is complete based on ACR level
107
- // ACR=1: Provisional token (requires 2FA)
108
- // ACR=2: Full authentication (2FA complete)
109
- const mfaVerified = acrLevel === '2';
110
- // Decode refresh token expiry if available
111
- let refreshTokenExpires;
112
- try {
113
- const refreshDecoded = (0, token_utils_1.decodeIdpAccessToken)(refresh_token);
114
- if (refreshDecoded?.exp) {
115
- refreshTokenExpires = (0, token_utils_1.expClaimToMs)(refreshDecoded.exp);
116
- }
117
- }
118
- catch {
119
- // Ignore - will use default expiry
120
- }
121
- // -------------------------------------------------------------------------
122
- // Create Redis Session
123
- // -------------------------------------------------------------------------
124
- // Using normalized field names (session-store handles backward compatibility)
125
- const sessionData = {
126
- userId,
127
- email,
128
- roles,
129
- // IDP tokens (normalized names)
130
- idpAccessToken: access_token,
131
- idpRefreshToken: refresh_token,
132
- idpAccessTokenExpires: (0, token_utils_1.expClaimToMs)(decoded.exp),
133
- idpRefreshTokenExpires: refreshTokenExpires,
134
- decodedAccessToken: decoded,
135
- // Bearer key ID from JWT header (NOT client_id from payload)
136
- bearerKeyId,
137
- // MFA state (normalized names)
138
- mfaVerified,
139
- authenticationMethods: amrClaims,
140
- authenticationLevel: acrLevel,
141
- // MFA timing info from token
142
- mfaCompletedAt: decoded.mfa_time ? (0, token_utils_1.expClaimToMs)(decoded.mfa_time) : undefined,
143
- mfaExpiresAt: decoded.mfa_expires ? (0, token_utils_1.expClaimToMs)(decoded.mfa_expires) : undefined,
144
- mfaValidityHours: decoded.mfa_validity_hours,
145
- };
146
- // Determine MFA method from IDP user info
147
- let mfaMethod;
148
- if (idpUser?.isEmailConfirmed) {
149
- mfaMethod = 'email';
150
- }
151
- else if (idpUser?.isSmsConfirmed) {
152
- mfaMethod = 'sms';
153
- }
154
- if (mfaMethod) {
155
- sessionData.mfaMethod = mfaMethod;
156
- }
157
- // Create the Redis session
158
- const redisSessionId = await (0, session_store_1.createSession)(sessionData);
159
- // -------------------------------------------------------------------------
160
- // Return User Object for NextAuth
161
- // -------------------------------------------------------------------------
162
- // NextAuth requires 'id' field - we use userId from IDP
163
- // The redisSessionId is passed through to the JWT callback
164
- return {
165
- id: userId,
166
- email,
167
- roles,
168
- redisSessionId: (0, auth_types_1.toRedisSessionId)(redisSessionId),
169
- mfaRequired: !mfaVerified,
170
- mfaMethod,
171
- };
172
- }
173
- // ============================================================================
174
- // HELPER FUNCTIONS
175
- // ============================================================================
176
- /**
177
- * Extract client headers from request for audit logging.
178
- */
179
- function extractClientHeaders(req) {
180
- const headers = {};
181
- // Extract client IP
182
- const forwardedFor = req?.headers?.['x-forwarded-for'];
183
- const realIp = req?.headers?.['x-real-ip'];
184
- if (forwardedFor) {
185
- const ip = Array.isArray(forwardedFor) ? forwardedFor[0] : forwardedFor.split(',')[0].trim();
186
- headers.ip = ip;
187
- }
188
- else if (realIp) {
189
- headers.ip = Array.isArray(realIp) ? realIp[0] : realIp;
190
- }
191
- // Extract User-Agent
192
- const userAgent = req?.headers?.['user-agent'];
193
- if (userAgent) {
194
- headers.userAgent = Array.isArray(userAgent) ? userAgent[0] : userAgent;
195
- }
196
- return headers;
197
- }
198
- /**
199
- * Build structured error response for frontend.
200
- *
201
- * The frontend expects a specific error structure to display
202
- * appropriate messages and handle things like lockout.
203
- */
204
- function buildAuthError(error) {
205
- if (!error) {
206
- return {
207
- success: false,
208
- error: {
209
- code: 'AUTH_ERROR',
210
- message: 'Authentication failed',
211
- details: {},
212
- },
213
- };
214
- }
215
- return {
216
- success: false,
217
- error: {
218
- code: error.code || 'AUTH_ERROR',
219
- message: error.message || 'Authentication failed',
220
- details: error.details || {},
221
- },
222
- };
223
- }
1
+ "use strict";
2
+ /**
3
+ * Credentials Provider
4
+ *
5
+ * Handles email/password authentication via PayEz IDP.
6
+ * Creates Redis session and returns minimal user object to NextAuth.
7
+ *
8
+ * FLOW:
9
+ * 1. User submits email/password
10
+ * 2. We call IDP /api/ExternalAuth/login
11
+ * 3. IDP returns tokens if credentials valid
12
+ * 4. We create Redis session with tokens
13
+ * 5. Return user object with redisSessionId to NextAuth
14
+ *
15
+ * @version 1.0.0
16
+ * @since auth-refactor-2026-01
17
+ */
18
+ var __importDefault = (this && this.__importDefault) || function (mod) {
19
+ return (mod && mod.__esModule) ? mod : { "default": mod };
20
+ };
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.createCredentialsProvider = createCredentialsProvider;
23
+ const credentials_1 = __importDefault(require("next-auth/providers/credentials"));
24
+ const session_store_1 = require("../../lib/session-store");
25
+ const idp_client_1 = require("../utils/idp-client");
26
+ const token_utils_1 = require("../utils/token-utils");
27
+ const auth_types_1 = require("../types/auth-types");
28
+ // NOTE: Using any for sessionData until Phase 3 normalizes types
29
+ // ============================================================================
30
+ // CREDENTIALS PROVIDER
31
+ // ============================================================================
32
+ /**
33
+ * Create the CredentialsProvider for NextAuth.
34
+ *
35
+ * This provider handles email/password login. The authorize function
36
+ * is called when a user submits the login form.
37
+ */
38
+ function createCredentialsProvider() {
39
+ return (0, credentials_1.default)({
40
+ id: 'credentials',
41
+ name: 'Credentials',
42
+ credentials: {
43
+ email: { label: 'Email', type: 'email' },
44
+ password: { label: 'Password', type: 'password' },
45
+ },
46
+ authorize: authorizeCredentials,
47
+ });
48
+ }
49
+ /**
50
+ * Authorize user with email/password.
51
+ *
52
+ * This is the core authentication function. It:
53
+ * 1. Validates credentials with IDP
54
+ * 2. Decodes the returned tokens
55
+ * 3. Creates a Redis session
56
+ * 4. Returns user info for NextAuth JWT
57
+ *
58
+ * @param credentials - Email and password from login form
59
+ * @param req - The incoming request (for IP/UA forwarding)
60
+ * @returns User object for NextAuth, or null/throws on failure
61
+ */
62
+ async function authorizeCredentials(credentials, req) {
63
+ // -------------------------------------------------------------------------
64
+ // Validate Input
65
+ // -------------------------------------------------------------------------
66
+ if (!credentials?.email || !credentials?.password) {
67
+ throw new Error('Email and password required');
68
+ }
69
+ const loginCredentials = {
70
+ email: credentials.email,
71
+ password: credentials.password,
72
+ };
73
+ // Extract client info for audit logging
74
+ const clientHeaders = extractClientHeaders(req);
75
+ // -------------------------------------------------------------------------
76
+ // Call IDP
77
+ // -------------------------------------------------------------------------
78
+ const loginResult = await (0, idp_client_1.idpLogin)(loginCredentials, clientHeaders);
79
+ if (!loginResult.success || !loginResult.result) {
80
+ // Build structured error for frontend
81
+ const errorResponse = buildAuthError(loginResult.error);
82
+ throw new Error(JSON.stringify(errorResponse));
83
+ }
84
+ const { access_token, refresh_token, user: idpUser } = loginResult.result;
85
+ // -------------------------------------------------------------------------
86
+ // Decode Token
87
+ // -------------------------------------------------------------------------
88
+ const decoded = (0, token_utils_1.decodeIdpAccessToken)(access_token);
89
+ if (!decoded) {
90
+ throw new Error('Failed to decode token');
91
+ }
92
+ // Extract kid from JWT header (CRITICAL: this is different from client_id in payload)
93
+ const bearerKeyId = (0, token_utils_1.extractKidFromToken)(access_token);
94
+ if (bearerKeyId) {
95
+ console.log('[CREDENTIALS] Extracted bearerKeyId (kid) from JWT header:', bearerKeyId);
96
+ }
97
+ else {
98
+ console.warn('[CREDENTIALS] No kid found in JWT header - token may be unsigned or malformed');
99
+ }
100
+ // Extract claims from token
101
+ const email = (0, token_utils_1.extractEmailFromToken)(decoded);
102
+ const roles = (0, token_utils_1.extractRolesFromToken)(decoded);
103
+ const amrClaims = (0, token_utils_1.extractAmrFromToken)(decoded);
104
+ const acrLevel = decoded.acr || '1';
105
+ const userId = decoded.sub;
106
+ // Check if 2FA is complete based on ACR level
107
+ // ACR=1: Provisional token (requires 2FA)
108
+ // ACR=2: Full authentication (2FA complete)
109
+ const mfaVerified = acrLevel === '2';
110
+ // Decode refresh token expiry if available
111
+ let refreshTokenExpires;
112
+ try {
113
+ const refreshDecoded = (0, token_utils_1.decodeIdpAccessToken)(refresh_token);
114
+ if (refreshDecoded?.exp) {
115
+ refreshTokenExpires = (0, token_utils_1.expClaimToMs)(refreshDecoded.exp);
116
+ }
117
+ }
118
+ catch {
119
+ // Ignore - will use default expiry
120
+ }
121
+ // -------------------------------------------------------------------------
122
+ // Create Redis Session
123
+ // -------------------------------------------------------------------------
124
+ // Using normalized field names (session-store handles backward compatibility)
125
+ const sessionData = {
126
+ userId,
127
+ email,
128
+ roles,
129
+ // IDP tokens (normalized names)
130
+ idpAccessToken: access_token,
131
+ idpRefreshToken: refresh_token,
132
+ idpAccessTokenExpires: (0, token_utils_1.expClaimToMs)(decoded.exp),
133
+ idpRefreshTokenExpires: refreshTokenExpires,
134
+ decodedAccessToken: decoded,
135
+ // Bearer key ID from JWT header (NOT client_id from payload)
136
+ bearerKeyId,
137
+ // MFA state (normalized names)
138
+ mfaVerified,
139
+ authenticationMethods: amrClaims,
140
+ authenticationLevel: acrLevel,
141
+ // MFA timing info from token
142
+ mfaCompletedAt: decoded.mfa_time ? (0, token_utils_1.expClaimToMs)(decoded.mfa_time) : undefined,
143
+ mfaExpiresAt: decoded.mfa_expires ? (0, token_utils_1.expClaimToMs)(decoded.mfa_expires) : undefined,
144
+ mfaValidityHours: decoded.mfa_validity_hours,
145
+ };
146
+ // Determine MFA method from IDP user info
147
+ let mfaMethod;
148
+ if (idpUser?.isEmailConfirmed) {
149
+ mfaMethod = 'email';
150
+ }
151
+ else if (idpUser?.isSmsConfirmed) {
152
+ mfaMethod = 'sms';
153
+ }
154
+ if (mfaMethod) {
155
+ sessionData.mfaMethod = mfaMethod;
156
+ }
157
+ // Create the Redis session
158
+ const redisSessionId = await (0, session_store_1.createSession)(sessionData);
159
+ // -------------------------------------------------------------------------
160
+ // Return User Object for NextAuth
161
+ // -------------------------------------------------------------------------
162
+ // NextAuth requires 'id' field - we use userId from IDP
163
+ // The redisSessionId is passed through to the JWT callback
164
+ return {
165
+ id: userId,
166
+ email,
167
+ roles,
168
+ redisSessionId: (0, auth_types_1.toRedisSessionId)(redisSessionId),
169
+ mfaRequired: !mfaVerified,
170
+ mfaMethod,
171
+ };
172
+ }
173
+ // ============================================================================
174
+ // HELPER FUNCTIONS
175
+ // ============================================================================
176
+ /**
177
+ * Extract client headers from request for audit logging.
178
+ */
179
+ function extractClientHeaders(req) {
180
+ const headers = {};
181
+ // Extract client IP
182
+ const forwardedFor = req?.headers?.['x-forwarded-for'];
183
+ const realIp = req?.headers?.['x-real-ip'];
184
+ if (forwardedFor) {
185
+ const ip = Array.isArray(forwardedFor) ? forwardedFor[0] : forwardedFor.split(',')[0].trim();
186
+ headers.ip = ip;
187
+ }
188
+ else if (realIp) {
189
+ headers.ip = Array.isArray(realIp) ? realIp[0] : realIp;
190
+ }
191
+ // Extract User-Agent
192
+ const userAgent = req?.headers?.['user-agent'];
193
+ if (userAgent) {
194
+ headers.userAgent = Array.isArray(userAgent) ? userAgent[0] : userAgent;
195
+ }
196
+ return headers;
197
+ }
198
+ /**
199
+ * Build structured error response for frontend.
200
+ *
201
+ * The frontend expects a specific error structure to display
202
+ * appropriate messages and handle things like lockout.
203
+ */
204
+ function buildAuthError(error) {
205
+ if (!error) {
206
+ return {
207
+ success: false,
208
+ error: {
209
+ code: 'AUTH_ERROR',
210
+ message: 'Authentication failed',
211
+ details: {},
212
+ },
213
+ };
214
+ }
215
+ return {
216
+ success: false,
217
+ error: {
218
+ code: error.code || 'AUTH_ERROR',
219
+ message: error.message || 'Authentication failed',
220
+ details: error.details || {},
221
+ },
222
+ };
223
+ }
@@ -120,7 +120,8 @@ async function getIDPClientConfig(forceRefresh = false) {
120
120
  }
121
121
  // Set IDENTITY_CLIENT_BASE_EXTERNAL_URL from cached config
122
122
  // AUTH_TRUST_HOST=true tells NextAuth to derive OAuth callback URLs from headers.
123
- if (redisConfig.baseClientUrl) {
123
+ // Only set if not already defined (allows deployment override for beta/staging)
124
+ if (redisConfig.baseClientUrl && !process.env.IDENTITY_CLIENT_BASE_EXTERNAL_URL) {
124
125
  process.env.IDENTITY_CLIENT_BASE_EXTERNAL_URL = redisConfig.baseClientUrl;
125
126
  }
126
127
  return redisConfig;
@@ -152,7 +153,8 @@ async function getIDPClientConfig(forceRefresh = false) {
152
153
  }
153
154
  // Set IDENTITY_CLIENT_BASE_EXTERNAL_URL from config
154
155
  // AUTH_TRUST_HOST=true tells NextAuth to derive OAuth callback URLs from headers.
155
- if (config.baseClientUrl) {
156
+ // Only set if not already defined (allows deployment override for beta/staging)
157
+ if (config.baseClientUrl && !process.env.IDENTITY_CLIENT_BASE_EXTERNAL_URL) {
156
158
  process.env.IDENTITY_CLIENT_BASE_EXTERNAL_URL = config.baseClientUrl;
157
159
  console.log("[IDP_CONFIG] Set IDENTITY_CLIENT_BASE_EXTERNAL_URL:", config.baseClientUrl);
158
160
  }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * =============================================================================
3
+ * VIBE ENTERPRISE AUTHENTICATION
4
+ * =============================================================================
5
+ *
6
+ * Server-side HMAC authentication for enterprise/service account requests.
7
+ * Validates incoming requests with X-Vibe-Client-Id, X-Vibe-Timestamp, and
8
+ * X-Vibe-Signature headers.
9
+ *
10
+ * Usage in Next.js API routes:
11
+ * import { validateEnterpriseAuth, hasEnterpriseAuthHeaders } from '@payez/next-mvp/vibe/enterprise-auth'
12
+ *
13
+ * export async function GET(request: NextRequest) {
14
+ * if (hasEnterpriseAuthHeaders(request)) {
15
+ * const auth = await validateEnterpriseAuth(request, ENTERPRISE_CLIENTS);
16
+ * if (!auth.success) {
17
+ * return NextResponse.json({ error: auth.error }, { status: 401 });
18
+ * }
19
+ * // Use auth.clientId for authenticated requests
20
+ * }
21
+ * }
22
+ *
23
+ * =============================================================================
24
+ */
25
+ import { NextRequest } from 'next/server';
26
+ /**
27
+ * Enterprise client credentials configuration
28
+ * Maps client IDs to their HMAC secret keys (base64-encoded)
29
+ */
30
+ export interface EnterpriseClientsConfig {
31
+ [clientId: string]: string;
32
+ }
33
+ export interface EnterpriseAuthResult {
34
+ success: boolean;
35
+ clientId?: string;
36
+ error?: string;
37
+ }
38
+ /**
39
+ * Validates enterprise HMAC authentication headers on incoming requests.
40
+ *
41
+ * Expected headers:
42
+ * - X-Vibe-Client-Id: The client identifier
43
+ * - X-Vibe-Timestamp: Unix timestamp in seconds
44
+ * - X-Vibe-Signature: HMAC-SHA256 signature of "{timestamp}|{method}|{path}"
45
+ *
46
+ * Security features:
47
+ * - Constant-time signature comparison (prevents timing attacks)
48
+ * - Timestamp validation with 5-minute window (prevents replay attacks)
49
+ * - Base64-encoded secret keys
50
+ *
51
+ * @param request - The Next.js request object
52
+ * @param enterpriseClients - Map of client IDs to secret keys
53
+ * @returns Authentication result with success status and client ID
54
+ *
55
+ * @example
56
+ * const CLIENTS = {
57
+ * 'vibe_abc123': 'base64SecretKey=='
58
+ * };
59
+ * const result = await validateEnterpriseAuth(request, CLIENTS);
60
+ * if (result.success) {
61
+ * console.log(`Authenticated client: ${result.clientId}`);
62
+ * }
63
+ */
64
+ export declare function validateEnterpriseAuth(request: NextRequest, enterpriseClients: EnterpriseClientsConfig): Promise<EnterpriseAuthResult>;
65
+ /**
66
+ * Checks if request has enterprise authentication headers.
67
+ * Does not validate - just checks if all required headers are present.
68
+ *
69
+ * @param request - The Next.js request object
70
+ * @returns True if all enterprise auth headers are present
71
+ *
72
+ * @example
73
+ * if (hasEnterpriseAuthHeaders(request)) {
74
+ * // Validate the headers
75
+ * const auth = await validateEnterpriseAuth(request, clients);
76
+ * } else {
77
+ * // Fall back to user session auth
78
+ * const token = await ensureFreshToken(request);
79
+ * }
80
+ */
81
+ export declare function hasEnterpriseAuthHeaders(request: NextRequest): boolean;
82
+ /**
83
+ * Generates HMAC signature for backend API requests.
84
+ * Used when frontend needs to proxy enterprise auth requests to backend
85
+ * with a different path (e.g., /api/vibe/* -> /v1/collections/*).
86
+ *
87
+ * @param clientId - The Vibe client ID
88
+ * @param secretKey - Base64-encoded HMAC secret key
89
+ * @param timestamp - Unix timestamp (seconds) as string
90
+ * @param method - HTTP method (GET, POST, etc)
91
+ * @param backendPath - The backend API path (e.g., "/v1/collections/agent_mail/tables")
92
+ * @returns HMAC signature for the backend request
93
+ *
94
+ * @example
95
+ * // Frontend received request for /api/vibe/agent_mail/tables
96
+ * // Need to call backend at /v1/collections/agent_mail/tables
97
+ * const signature = generateBackendHmacSignature(
98
+ * 'vibe_abc123',
99
+ * 'base64SecretKey==',
100
+ * '1234567890',
101
+ * 'GET',
102
+ * '/v1/collections/agent_mail/tables'
103
+ * );
104
+ * // Use signature in backend request headers
105
+ */
106
+ export declare function generateBackendHmacSignature(clientId: string, secretKey: string, timestamp: string, method: string, backendPath: string): string;