@vybestack/llxprt-code-auth 0.10.0-nightly.260613.1adad3b34
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/.last_build +0 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/src/auth-precedence-resolver.d.ts +147 -0
- package/dist/src/auth-precedence-resolver.js +542 -0
- package/dist/src/auth-precedence-resolver.js.map +1 -0
- package/dist/src/flows/anthropic-device-flow.d.ts +57 -0
- package/dist/src/flows/anthropic-device-flow.js +231 -0
- package/dist/src/flows/anthropic-device-flow.js.map +1 -0
- package/dist/src/flows/codex-device-flow.d.ts +114 -0
- package/dist/src/flows/codex-device-flow.js +437 -0
- package/dist/src/flows/codex-device-flow.js.map +1 -0
- package/dist/src/flows/qwen-device-flow.d.ts +45 -0
- package/dist/src/flows/qwen-device-flow.js +183 -0
- package/dist/src/flows/qwen-device-flow.js.map +1 -0
- package/dist/src/index.d.ts +34 -0
- package/dist/src/index.js +26 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/interfaces/debug-logger.d.ts +31 -0
- package/dist/src/interfaces/debug-logger.js +6 -0
- package/dist/src/interfaces/debug-logger.js.map +1 -0
- package/dist/src/interfaces/index.d.ts +18 -0
- package/dist/src/interfaces/index.js +10 -0
- package/dist/src/interfaces/index.js.map +1 -0
- package/dist/src/interfaces/provider-key-storage.d.ts +26 -0
- package/dist/src/interfaces/provider-key-storage.js +6 -0
- package/dist/src/interfaces/provider-key-storage.js.map +1 -0
- package/dist/src/interfaces/runtime-context.d.ts +37 -0
- package/dist/src/interfaces/runtime-context.js +6 -0
- package/dist/src/interfaces/runtime-context.js.map +1 -0
- package/dist/src/interfaces/secure-store.d.ts +47 -0
- package/dist/src/interfaces/secure-store.js +6 -0
- package/dist/src/interfaces/secure-store.js.map +1 -0
- package/dist/src/interfaces/settings-service.d.ts +25 -0
- package/dist/src/interfaces/settings-service.js +6 -0
- package/dist/src/interfaces/settings-service.js.map +1 -0
- package/dist/src/keyring-token-store.d.ts +96 -0
- package/dist/src/keyring-token-store.js +391 -0
- package/dist/src/keyring-token-store.js.map +1 -0
- package/dist/src/oauth-errors.d.ts +173 -0
- package/dist/src/oauth-errors.js +465 -0
- package/dist/src/oauth-errors.js.map +1 -0
- package/dist/src/precedence.d.ts +115 -0
- package/dist/src/precedence.js +278 -0
- package/dist/src/precedence.js.map +1 -0
- package/dist/src/proxy/framing.d.ts +35 -0
- package/dist/src/proxy/framing.js +86 -0
- package/dist/src/proxy/framing.js.map +1 -0
- package/dist/src/proxy/proxy-provider-key-storage.d.ts +23 -0
- package/dist/src/proxy/proxy-provider-key-storage.js +41 -0
- package/dist/src/proxy/proxy-provider-key-storage.js.map +1 -0
- package/dist/src/proxy/proxy-socket-client.d.ts +43 -0
- package/dist/src/proxy/proxy-socket-client.js +219 -0
- package/dist/src/proxy/proxy-socket-client.js.map +1 -0
- package/dist/src/proxy/proxy-token-store.d.ts +39 -0
- package/dist/src/proxy/proxy-token-store.js +87 -0
- package/dist/src/proxy/proxy-token-store.js.map +1 -0
- package/dist/src/token-merge.d.ts +16 -0
- package/dist/src/token-merge.js +13 -0
- package/dist/src/token-merge.js.map +1 -0
- package/dist/src/token-sanitization.d.ts +16 -0
- package/dist/src/token-sanitization.js +10 -0
- package/dist/src/token-sanitization.js.map +1 -0
- package/dist/src/token-store.d.ts +93 -0
- package/dist/src/token-store.js +7 -0
- package/dist/src/token-store.js.map +1 -0
- package/dist/src/types.d.ts +204 -0
- package/dist/src/types.js +86 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic OAuth 2.0 Device Flow Implementation
|
|
3
|
+
*
|
|
4
|
+
* Implements OAuth 2.0 device authorization grant flow for Anthropic Claude API.
|
|
5
|
+
* Based on the OAuth 2.0 Device Authorization Grant specification (RFC 8628).
|
|
6
|
+
*/
|
|
7
|
+
import { createHash, randomBytes } from 'crypto';
|
|
8
|
+
import { URL } from 'node:url';
|
|
9
|
+
/**
|
|
10
|
+
* Anthropic-specific OAuth 2.0 device flow implementation.
|
|
11
|
+
* Handles authentication for Claude API access.
|
|
12
|
+
*/
|
|
13
|
+
export class AnthropicDeviceFlow {
|
|
14
|
+
config;
|
|
15
|
+
codeVerifier;
|
|
16
|
+
_codeChallenge;
|
|
17
|
+
state;
|
|
18
|
+
redirectUri;
|
|
19
|
+
revokeToken;
|
|
20
|
+
constructor(config) {
|
|
21
|
+
const defaultConfig = {
|
|
22
|
+
clientId: '9d1c250a-e61b-44d9-88ed-5944d1962f5e', // Anthropic's public OAuth client ID
|
|
23
|
+
authorizationEndpoint: 'https://claude.ai/oauth/authorize', // Use claude.ai like OpenCode's "max" mode
|
|
24
|
+
tokenEndpoint: 'https://console.anthropic.com/v1/oauth/token',
|
|
25
|
+
scopes: ['org:create_api_key', 'user:profile', 'user:inference'],
|
|
26
|
+
};
|
|
27
|
+
this.config = { ...defaultConfig, ...config };
|
|
28
|
+
this.redirectUri = 'https://console.anthropic.com/oauth/code/callback';
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Generates PKCE code verifier and challenge using S256 method
|
|
32
|
+
*/
|
|
33
|
+
generatePKCE() {
|
|
34
|
+
// Generate a random code verifier (43-128 characters)
|
|
35
|
+
const _verifier = randomBytes(32).toString('base64url');
|
|
36
|
+
this.codeVerifier = _verifier;
|
|
37
|
+
// Generate code challenge using S256 (SHA256 hash)
|
|
38
|
+
const challenge = createHash('sha256')
|
|
39
|
+
.update(_verifier)
|
|
40
|
+
.digest('base64url');
|
|
41
|
+
this._codeChallenge = challenge;
|
|
42
|
+
// Store challenge for potential future use
|
|
43
|
+
void this._codeChallenge;
|
|
44
|
+
return { verifier: _verifier, challenge };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Initiates the OAuth flow by constructing the authorization URL.
|
|
48
|
+
* Since Anthropic doesn't have a device flow, we simulate it with authorization code flow.
|
|
49
|
+
*/
|
|
50
|
+
async initiateDeviceFlow(redirectUri) {
|
|
51
|
+
// Generate PKCE parameters
|
|
52
|
+
const { verifier, challenge } = this.generatePKCE();
|
|
53
|
+
// Use verifier as state like OpenCode does
|
|
54
|
+
this.state = verifier; // Store for later use in token exchange
|
|
55
|
+
this.redirectUri =
|
|
56
|
+
redirectUri ?? 'https://console.anthropic.com/oauth/code/callback';
|
|
57
|
+
// Build authorization URL with PKCE parameters
|
|
58
|
+
const params = new URLSearchParams({
|
|
59
|
+
code: 'true',
|
|
60
|
+
client_id: this.config.clientId,
|
|
61
|
+
response_type: 'code',
|
|
62
|
+
redirect_uri: this.redirectUri,
|
|
63
|
+
scope: this.config.scopes.join(' '),
|
|
64
|
+
code_challenge: challenge,
|
|
65
|
+
code_challenge_method: 'S256',
|
|
66
|
+
state: verifier, // Use verifier as state like OpenCode
|
|
67
|
+
});
|
|
68
|
+
const authUrl = `${this.config.authorizationEndpoint}?${params.toString()}`;
|
|
69
|
+
// Return a simulated device code response with the authorization URL
|
|
70
|
+
// The user will need to manually visit this URL and authorize
|
|
71
|
+
return {
|
|
72
|
+
device_code: verifier, // Use verifier as a tracking ID
|
|
73
|
+
user_code: 'ANTHROPIC', // Display code for user
|
|
74
|
+
verification_uri: 'https://console.anthropic.com/oauth/authorize',
|
|
75
|
+
verification_uri_complete: authUrl,
|
|
76
|
+
expires_in: 1800, // 30 minutes
|
|
77
|
+
interval: 5, // 5 seconds polling interval
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Exchange authorization code for access token (PKCE flow)
|
|
82
|
+
*/
|
|
83
|
+
async exchangeCodeForToken(authCodeWithState) {
|
|
84
|
+
if (!this.codeVerifier) {
|
|
85
|
+
throw new Error('No PKCE code verifier found - OAuth flow not initialized');
|
|
86
|
+
}
|
|
87
|
+
// OpenCode splits the code and state - format: code#state
|
|
88
|
+
const splits = authCodeWithState.split('#');
|
|
89
|
+
const authCode = splits[0];
|
|
90
|
+
const stateFromResponse = splits[1] || this.state; // Use state from response if available
|
|
91
|
+
// OpenCode sends JSON, not form-encoded!
|
|
92
|
+
const requestBody = {
|
|
93
|
+
grant_type: 'authorization_code',
|
|
94
|
+
code: authCode,
|
|
95
|
+
state: stateFromResponse, // Include state in the request
|
|
96
|
+
client_id: this.config.clientId,
|
|
97
|
+
redirect_uri: this.redirectUri,
|
|
98
|
+
code_verifier: this.codeVerifier,
|
|
99
|
+
};
|
|
100
|
+
const response = await fetch(this.config.tokenEndpoint, {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
headers: {
|
|
103
|
+
'Content-Type': 'application/json', // JSON, not form-encoded!
|
|
104
|
+
},
|
|
105
|
+
body: JSON.stringify(requestBody), // Send as JSON
|
|
106
|
+
});
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
const error = await response.text();
|
|
109
|
+
throw new Error(`Failed to exchange authorization code: ${error}`);
|
|
110
|
+
}
|
|
111
|
+
const data = (await response.json());
|
|
112
|
+
return this.mapTokenResponse(data);
|
|
113
|
+
}
|
|
114
|
+
getState() {
|
|
115
|
+
if (!this.state) {
|
|
116
|
+
throw new Error('OAuth flow not initialized');
|
|
117
|
+
}
|
|
118
|
+
return this.state;
|
|
119
|
+
}
|
|
120
|
+
buildAuthorizationUrl(redirectUri) {
|
|
121
|
+
if (!this._codeChallenge || !this.state) {
|
|
122
|
+
throw new Error('OAuth flow not initialized');
|
|
123
|
+
}
|
|
124
|
+
const redirect = new URL(redirectUri);
|
|
125
|
+
if (redirect.hostname !== '127.0.0.1' &&
|
|
126
|
+
redirect.hostname !== 'localhost') {
|
|
127
|
+
throw new Error('Only localhost redirect URIs are supported for Anthropic OAuth');
|
|
128
|
+
}
|
|
129
|
+
this.redirectUri = redirectUri;
|
|
130
|
+
const params = new URLSearchParams({
|
|
131
|
+
code: 'true',
|
|
132
|
+
client_id: this.config.clientId,
|
|
133
|
+
response_type: 'code',
|
|
134
|
+
redirect_uri: redirectUri,
|
|
135
|
+
scope: this.config.scopes.join(' '),
|
|
136
|
+
code_challenge: this._codeChallenge,
|
|
137
|
+
code_challenge_method: 'S256',
|
|
138
|
+
state: this.state,
|
|
139
|
+
});
|
|
140
|
+
return `${this.config.authorizationEndpoint}?${params.toString()}`;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Polls for the access token after user authorization.
|
|
144
|
+
*/
|
|
145
|
+
async pollForToken(deviceCode) {
|
|
146
|
+
const startTime = Date.now();
|
|
147
|
+
const expiresIn = 1800 * 1000; // 30 minutes in milliseconds
|
|
148
|
+
const interval = 5000; // 5 seconds default polling interval
|
|
149
|
+
while (Date.now() - startTime < expiresIn) {
|
|
150
|
+
try {
|
|
151
|
+
const response = await fetch(this.config.tokenEndpoint, {
|
|
152
|
+
method: 'POST',
|
|
153
|
+
headers: {
|
|
154
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
155
|
+
},
|
|
156
|
+
body: new URLSearchParams({
|
|
157
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
158
|
+
device_code: deviceCode,
|
|
159
|
+
client_id: this.config.clientId,
|
|
160
|
+
}),
|
|
161
|
+
});
|
|
162
|
+
if (response.ok) {
|
|
163
|
+
const data = (await response.json());
|
|
164
|
+
return this.mapTokenResponse(data);
|
|
165
|
+
}
|
|
166
|
+
const error = (await response.json());
|
|
167
|
+
// Handle polling errors
|
|
168
|
+
let sleepMs = interval;
|
|
169
|
+
if (error.error === 'authorization_pending') {
|
|
170
|
+
// Continue polling
|
|
171
|
+
}
|
|
172
|
+
else if (error.error === 'slow_down') {
|
|
173
|
+
sleepMs = interval * 2;
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
// Handle other errors
|
|
177
|
+
throw new Error(`Token polling failed: ${error.error_description ?? error.error}`);
|
|
178
|
+
}
|
|
179
|
+
await new Promise((resolve) => setTimeout(resolve, sleepMs));
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
if (error instanceof Error &&
|
|
183
|
+
error.message.includes('Token polling failed')) {
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
// Network errors - continue polling
|
|
187
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
throw new Error('Authorization timeout - user did not complete authentication');
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Refreshes an expired access token using a refresh token.
|
|
194
|
+
*/
|
|
195
|
+
async refreshToken(refreshToken) {
|
|
196
|
+
const response = await fetch(this.config.tokenEndpoint, {
|
|
197
|
+
method: 'POST',
|
|
198
|
+
headers: {
|
|
199
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
200
|
+
},
|
|
201
|
+
body: new URLSearchParams({
|
|
202
|
+
grant_type: 'refresh_token',
|
|
203
|
+
refresh_token: refreshToken,
|
|
204
|
+
client_id: this.config.clientId,
|
|
205
|
+
}),
|
|
206
|
+
});
|
|
207
|
+
if (!response.ok) {
|
|
208
|
+
const error = await response.text();
|
|
209
|
+
throw new Error(`Failed to refresh Anthropic token: ${error}`);
|
|
210
|
+
}
|
|
211
|
+
const data = (await response.json());
|
|
212
|
+
return this.mapTokenResponse(data);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Maps Anthropic's token response to our standard OAuthToken format.
|
|
216
|
+
*/
|
|
217
|
+
mapTokenResponse(data) {
|
|
218
|
+
const expiresIn = data.expires_in;
|
|
219
|
+
const expiresInSeconds = typeof expiresIn === 'number' && !isNaN(expiresIn) && expiresIn > 0
|
|
220
|
+
? expiresIn
|
|
221
|
+
: 3600;
|
|
222
|
+
return {
|
|
223
|
+
access_token: data.access_token,
|
|
224
|
+
expiry: Math.floor(Date.now() / 1000) + expiresInSeconds,
|
|
225
|
+
refresh_token: data.refresh_token,
|
|
226
|
+
scope: data.scope,
|
|
227
|
+
token_type: 'Bearer',
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=anthropic-device-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic-device-flow.js","sourceRoot":"","sources":["../../../src/flows/anthropic-device-flow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Vybestack LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import type { IDebugLogger } from '../interfaces/debug-logger.js';
|
|
7
|
+
import { type CodexOAuthToken } from '../types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Codex-specific OAuth configuration
|
|
10
|
+
* Exported for reuse by CLI and other consumers to ensure single source of truth
|
|
11
|
+
*/
|
|
12
|
+
export declare const CODEX_CONFIG: {
|
|
13
|
+
readonly clientId: "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
14
|
+
readonly issuer: "https://auth.openai.com";
|
|
15
|
+
readonly tokenEndpoint: "https://auth.openai.com/oauth/token";
|
|
16
|
+
readonly authorizationEndpoint: "https://auth.openai.com/oauth/authorize";
|
|
17
|
+
readonly deviceAuthUserCodeEndpoint: "https://auth.openai.com/api/accounts/deviceauth/usercode";
|
|
18
|
+
readonly deviceAuthTokenEndpoint: "https://auth.openai.com/api/accounts/deviceauth/token";
|
|
19
|
+
readonly deviceAuthCallbackUri: "https://auth.openai.com/deviceauth/callback";
|
|
20
|
+
readonly scopes: readonly ["openid", "profile", "email", "offline_access"];
|
|
21
|
+
readonly originator: "codex_cli_rs";
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Codex OAuth PKCE flow implementation
|
|
25
|
+
* Implements OAuth 2.0 Authorization Code flow with PKCE for Codex authentication
|
|
26
|
+
*/
|
|
27
|
+
export declare class CodexDeviceFlow {
|
|
28
|
+
private logger;
|
|
29
|
+
private codeVerifiers;
|
|
30
|
+
private static readonly NO_OP_LOGGER;
|
|
31
|
+
constructor(options?: {
|
|
32
|
+
logger?: IDebugLogger;
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* Build authorization URL for browser-based OAuth flow
|
|
36
|
+
* @param redirectUri Callback URL for OAuth redirect
|
|
37
|
+
* @param state Random state parameter for CSRF protection
|
|
38
|
+
* @returns Authorization URL to open in browser
|
|
39
|
+
*/
|
|
40
|
+
buildAuthorizationUrl(redirectUri: string, state: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Exchange authorization code for OAuth tokens
|
|
43
|
+
* @param authCode Authorization code from OAuth callback
|
|
44
|
+
* @param redirectUri Callback URL (must match the one used in authorization request)
|
|
45
|
+
* @param state State parameter from OAuth callback
|
|
46
|
+
* @returns Validated CodexOAuthToken with account_id
|
|
47
|
+
* @throws Error if code verifier not found for state or token exchange fails
|
|
48
|
+
*/
|
|
49
|
+
exchangeCodeForToken(authCode: string, redirectUri: string, state: string): Promise<CodexOAuthToken>;
|
|
50
|
+
/**
|
|
51
|
+
* POST to the token endpoint and return a validated CodexTokenResponse.
|
|
52
|
+
* @throws Error if the HTTP request fails or the response is not OK
|
|
53
|
+
*/
|
|
54
|
+
private performTokenExchange;
|
|
55
|
+
/**
|
|
56
|
+
* Validate token response, extract account_id, and build a CodexOAuthToken.
|
|
57
|
+
* @throws Error if id_token is missing or account_id cannot be extracted
|
|
58
|
+
*/
|
|
59
|
+
private buildCodexToken;
|
|
60
|
+
/**
|
|
61
|
+
* Refresh an expired access token using refresh token
|
|
62
|
+
* @param refreshToken Valid refresh token
|
|
63
|
+
* @returns New CodexOAuthToken with updated expiry
|
|
64
|
+
* @throws Error if refresh fails or id_token missing
|
|
65
|
+
*/
|
|
66
|
+
refreshToken(refreshToken: string): Promise<CodexOAuthToken>;
|
|
67
|
+
/**
|
|
68
|
+
* Extract account_id from id_token JWT without external libraries
|
|
69
|
+
* JWT format: header.payload.signature (base64url encoded)
|
|
70
|
+
* @param idToken JWT id_token from OAuth response
|
|
71
|
+
* @returns account_id extracted from JWT claims
|
|
72
|
+
* @throws Error if JWT format invalid or account_id not found
|
|
73
|
+
*/
|
|
74
|
+
private extractAccountIdFromIdToken;
|
|
75
|
+
/**
|
|
76
|
+
* Helper to throw error when id_token is missing
|
|
77
|
+
* @throws Error indicating id_token required
|
|
78
|
+
*/
|
|
79
|
+
private throwMissingAccountId;
|
|
80
|
+
/**
|
|
81
|
+
* Request a user code for device authorization flow (browserless authentication)
|
|
82
|
+
* @returns Device code response with user_code and device_auth_id
|
|
83
|
+
*/
|
|
84
|
+
requestDeviceCode(): Promise<{
|
|
85
|
+
device_auth_id: string;
|
|
86
|
+
user_code: string;
|
|
87
|
+
interval: number;
|
|
88
|
+
}>;
|
|
89
|
+
/**
|
|
90
|
+
* Poll for token using device authorization
|
|
91
|
+
* @param deviceAuthId Device authorization ID
|
|
92
|
+
* @param userCode User code from device flow
|
|
93
|
+
* @param intervalSeconds Polling interval in seconds
|
|
94
|
+
* @returns Authorization code and PKCE codes for token exchange
|
|
95
|
+
*/
|
|
96
|
+
pollForDeviceToken(deviceAuthId: string, userCode: string, intervalSeconds?: number): Promise<{
|
|
97
|
+
authorization_code: string;
|
|
98
|
+
code_verifier: string;
|
|
99
|
+
code_challenge: string;
|
|
100
|
+
}>;
|
|
101
|
+
/**
|
|
102
|
+
* Complete device authorization flow by exchanging authorization code for tokens
|
|
103
|
+
* @param authorizationCode Authorization code from polling response
|
|
104
|
+
* @param codeVerifier PKCE code verifier from polling response
|
|
105
|
+
* @param redirectUri OAuth redirect URI
|
|
106
|
+
* @returns Complete OAuth token with access_token, refresh_token, etc.
|
|
107
|
+
*/
|
|
108
|
+
completeDeviceAuth(authorizationCode: string, codeVerifier: string, redirectUri: string): Promise<CodexOAuthToken>;
|
|
109
|
+
/**
|
|
110
|
+
* Generate PKCE code verifier and challenge
|
|
111
|
+
* @returns Object containing verifier and challenge strings
|
|
112
|
+
*/
|
|
113
|
+
private generatePKCE;
|
|
114
|
+
}
|