n8n-nodes-jygse-vw-weconnect 0.1.2 → 0.1.4
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.
|
@@ -141,21 +141,43 @@ class VwWeConnect {
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
exports.VwWeConnect = VwWeConnect;
|
|
144
|
-
// VW OAuth2 Configuration
|
|
145
|
-
const VW_CLIENT_ID = '
|
|
146
|
-
const VW_SCOPE = 'openid profile
|
|
144
|
+
// VW OAuth2 Configuration (Updated January 2026)
|
|
145
|
+
const VW_CLIENT_ID = 'a24fba63-34b3-4d43-b181-942111e6bda8@apps_vw-dilab_com';
|
|
146
|
+
const VW_SCOPE = 'openid profile badge cars dealers birthdate vin';
|
|
147
147
|
const VW_REDIRECT_URI = 'weconnect://authenticated';
|
|
148
|
+
const VW_RESPONSE_TYPE = 'code id_token token';
|
|
149
|
+
// Generate PKCE code verifier and challenge
|
|
150
|
+
function generateCodeVerifier() {
|
|
151
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
|
|
152
|
+
let result = '';
|
|
153
|
+
for (let i = 0; i < 64; i++) {
|
|
154
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
155
|
+
}
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
async function generateCodeChallenge(verifier) {
|
|
159
|
+
// Simple base64url encoding of SHA256 hash
|
|
160
|
+
// Since we can't use crypto directly, we'll use a simplified approach
|
|
161
|
+
// For now, use plain verifier (S256 would be better but requires crypto)
|
|
162
|
+
return verifier;
|
|
163
|
+
}
|
|
148
164
|
async function vwLogin(context, email, password) {
|
|
149
165
|
try {
|
|
150
|
-
//
|
|
166
|
+
// Generate PKCE values
|
|
167
|
+
const codeVerifier = generateCodeVerifier();
|
|
168
|
+
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
169
|
+
const stateParam = generateNonce();
|
|
170
|
+
// Step 1: Get authorization page - this now returns Auth0 login page
|
|
151
171
|
const authorizeUrl = 'https://identity.vwgroup.io/oidc/v1/authorize';
|
|
152
172
|
const authorizeParams = new URLSearchParams({
|
|
153
173
|
client_id: VW_CLIENT_ID,
|
|
154
174
|
scope: VW_SCOPE,
|
|
155
|
-
response_type:
|
|
175
|
+
response_type: VW_RESPONSE_TYPE,
|
|
156
176
|
redirect_uri: VW_REDIRECT_URI,
|
|
157
177
|
nonce: generateNonce(),
|
|
158
|
-
state:
|
|
178
|
+
state: stateParam,
|
|
179
|
+
code_challenge: codeChallenge,
|
|
180
|
+
code_challenge_method: 'plain',
|
|
159
181
|
});
|
|
160
182
|
const authorizeResponse = await context.helpers.httpRequest({
|
|
161
183
|
method: 'GET',
|
|
@@ -168,15 +190,19 @@ async function vwLogin(context, email, password) {
|
|
|
168
190
|
returnFullResponse: true,
|
|
169
191
|
ignoreHttpStatusErrors: true,
|
|
170
192
|
});
|
|
171
|
-
// Extract
|
|
172
|
-
// Handle both string response and object with body property
|
|
193
|
+
// Extract response body and check for redirect
|
|
173
194
|
let htmlContent;
|
|
195
|
+
let currentUrl = '';
|
|
174
196
|
if (typeof authorizeResponse === 'string') {
|
|
175
197
|
htmlContent = authorizeResponse;
|
|
176
198
|
}
|
|
177
199
|
else if (authorizeResponse && typeof authorizeResponse === 'object') {
|
|
178
200
|
const respObj = authorizeResponse;
|
|
179
|
-
|
|
201
|
+
const respHeaders = respObj.headers;
|
|
202
|
+
// Check for redirect in headers
|
|
203
|
+
if (respHeaders && respHeaders.location) {
|
|
204
|
+
currentUrl = respHeaders.location;
|
|
205
|
+
}
|
|
180
206
|
if (respObj.body && typeof respObj.body === 'string') {
|
|
181
207
|
htmlContent = respObj.body;
|
|
182
208
|
}
|
|
@@ -184,94 +210,172 @@ async function vwLogin(context, email, password) {
|
|
|
184
210
|
htmlContent = respObj.data;
|
|
185
211
|
}
|
|
186
212
|
else {
|
|
187
|
-
// Serialize the object to see its structure in the error
|
|
188
213
|
htmlContent = JSON.stringify(respObj);
|
|
189
214
|
}
|
|
190
215
|
}
|
|
191
216
|
else {
|
|
192
217
|
htmlContent = String(authorizeResponse);
|
|
193
218
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
if
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
const csrf = csrfMatch[1];
|
|
203
|
-
const relayState = relayStateMatch ? relayStateMatch[1] : '';
|
|
204
|
-
const hmac = hmacMatch ? hmacMatch[1] : '';
|
|
205
|
-
// Step 2: Submit email
|
|
206
|
-
const identifierResponse = await context.helpers.httpRequest({
|
|
207
|
-
method: 'POST',
|
|
208
|
-
url: 'https://identity.vwgroup.io/signin-service/v1/signin/login/identifier',
|
|
209
|
-
headers: {
|
|
210
|
-
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
|
|
211
|
-
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
212
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
213
|
-
},
|
|
214
|
-
body: new URLSearchParams({
|
|
215
|
-
_csrf: csrf,
|
|
216
|
-
relayState: relayState,
|
|
217
|
-
hmac: hmac,
|
|
218
|
-
email: email,
|
|
219
|
-
}).toString(),
|
|
220
|
-
encoding: 'text',
|
|
221
|
-
returnFullResponse: true,
|
|
222
|
-
ignoreHttpStatusErrors: true,
|
|
223
|
-
});
|
|
224
|
-
// Extract new CSRF for password submission
|
|
225
|
-
let identifierHtml;
|
|
226
|
-
if (typeof identifierResponse === 'string') {
|
|
227
|
-
identifierHtml = identifierResponse;
|
|
219
|
+
// Try to extract state token from Auth0 page (new flow)
|
|
220
|
+
// Look for state in URL or in hidden form field
|
|
221
|
+
let stateToken = '';
|
|
222
|
+
// Check if we were redirected to /u/login
|
|
223
|
+
const stateUrlMatch = currentUrl.match(/state=([^&]+)/);
|
|
224
|
+
if (stateUrlMatch) {
|
|
225
|
+
stateToken = decodeURIComponent(stateUrlMatch[1]);
|
|
228
226
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
227
|
+
// Also try to find state in the HTML
|
|
228
|
+
if (!stateToken) {
|
|
229
|
+
const stateHtmlMatch = htmlContent.match(/name="state"\s+value="([^"]+)"/);
|
|
230
|
+
if (stateHtmlMatch) {
|
|
231
|
+
stateToken = stateHtmlMatch[1];
|
|
232
|
+
}
|
|
232
233
|
}
|
|
233
|
-
|
|
234
|
-
|
|
234
|
+
// Try to find state in form action URL
|
|
235
|
+
if (!stateToken) {
|
|
236
|
+
const formActionMatch = htmlContent.match(/action="[^"]*\?state=([^"&]+)/);
|
|
237
|
+
if (formActionMatch) {
|
|
238
|
+
stateToken = decodeURIComponent(formActionMatch[1]);
|
|
239
|
+
}
|
|
235
240
|
}
|
|
236
|
-
|
|
237
|
-
const
|
|
238
|
-
const
|
|
239
|
-
const
|
|
240
|
-
const relayState2 = relayState2Match ? relayState2Match[1] : relayState;
|
|
241
|
-
const hmac2 = hmac2Match ? hmac2Match[1] : hmac;
|
|
242
|
-
// Step 3: Submit password
|
|
243
|
-
const authResponse = await context.helpers.httpRequest({
|
|
244
|
-
method: 'POST',
|
|
245
|
-
url: 'https://identity.vwgroup.io/signin-service/v1/signin/login/authenticate',
|
|
246
|
-
headers: {
|
|
247
|
-
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
|
|
248
|
-
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
249
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
250
|
-
},
|
|
251
|
-
body: new URLSearchParams({
|
|
252
|
-
_csrf: csrf2,
|
|
253
|
-
relayState: relayState2,
|
|
254
|
-
hmac: hmac2,
|
|
255
|
-
email: email,
|
|
256
|
-
password: password,
|
|
257
|
-
}).toString(),
|
|
258
|
-
encoding: 'text',
|
|
259
|
-
returnFullResponse: true,
|
|
260
|
-
ignoreHttpStatusErrors: true,
|
|
261
|
-
});
|
|
262
|
-
// Get the redirect URL which contains the authorization code
|
|
241
|
+
// Try legacy CSRF-based flow first
|
|
242
|
+
const csrfMatch = htmlContent.match(/name="_csrf"\s+value="([^"]+)"/);
|
|
243
|
+
const relayStateMatch = htmlContent.match(/name="relayState"\s+value="([^"]+)"/);
|
|
244
|
+
const hmacMatch = htmlContent.match(/name="hmac"\s+value="([^"]+)"/);
|
|
263
245
|
let redirectUrl = '';
|
|
264
246
|
let authHtml = '';
|
|
265
|
-
if (
|
|
266
|
-
|
|
247
|
+
if (csrfMatch) {
|
|
248
|
+
// Legacy flow with CSRF token
|
|
249
|
+
const csrf = csrfMatch[1];
|
|
250
|
+
const relayState = relayStateMatch ? relayStateMatch[1] : '';
|
|
251
|
+
const hmac = hmacMatch ? hmacMatch[1] : '';
|
|
252
|
+
// Step 2: Submit email
|
|
253
|
+
const identifierResponse = await context.helpers.httpRequest({
|
|
254
|
+
method: 'POST',
|
|
255
|
+
url: 'https://identity.vwgroup.io/signin-service/v1/signin/login/identifier',
|
|
256
|
+
headers: {
|
|
257
|
+
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
|
|
258
|
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
259
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
260
|
+
},
|
|
261
|
+
body: new URLSearchParams({
|
|
262
|
+
_csrf: csrf,
|
|
263
|
+
relayState: relayState,
|
|
264
|
+
hmac: hmac,
|
|
265
|
+
email: email,
|
|
266
|
+
}).toString(),
|
|
267
|
+
encoding: 'text',
|
|
268
|
+
returnFullResponse: true,
|
|
269
|
+
ignoreHttpStatusErrors: true,
|
|
270
|
+
});
|
|
271
|
+
let identifierHtml;
|
|
272
|
+
if (typeof identifierResponse === 'string') {
|
|
273
|
+
identifierHtml = identifierResponse;
|
|
274
|
+
}
|
|
275
|
+
else if (identifierResponse && typeof identifierResponse === 'object') {
|
|
276
|
+
const respObj = identifierResponse;
|
|
277
|
+
identifierHtml = respObj.body || JSON.stringify(respObj);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
identifierHtml = String(identifierResponse);
|
|
281
|
+
}
|
|
282
|
+
const csrf2Match = identifierHtml.match(/name="_csrf"\s+value="([^"]+)"/);
|
|
283
|
+
const relayState2Match = identifierHtml.match(/name="relayState"\s+value="([^"]+)"/);
|
|
284
|
+
const hmac2Match = identifierHtml.match(/name="hmac"\s+value="([^"]+)"/);
|
|
285
|
+
const csrf2 = csrf2Match ? csrf2Match[1] : csrf;
|
|
286
|
+
const relayState2 = relayState2Match ? relayState2Match[1] : relayState;
|
|
287
|
+
const hmac2 = hmac2Match ? hmac2Match[1] : hmac;
|
|
288
|
+
// Step 3: Submit password
|
|
289
|
+
const authResponse = await context.helpers.httpRequest({
|
|
290
|
+
method: 'POST',
|
|
291
|
+
url: 'https://identity.vwgroup.io/signin-service/v1/signin/login/authenticate',
|
|
292
|
+
headers: {
|
|
293
|
+
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
|
|
294
|
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
295
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
296
|
+
},
|
|
297
|
+
body: new URLSearchParams({
|
|
298
|
+
_csrf: csrf2,
|
|
299
|
+
relayState: relayState2,
|
|
300
|
+
hmac: hmac2,
|
|
301
|
+
email: email,
|
|
302
|
+
password: password,
|
|
303
|
+
}).toString(),
|
|
304
|
+
encoding: 'text',
|
|
305
|
+
returnFullResponse: true,
|
|
306
|
+
ignoreHttpStatusErrors: true,
|
|
307
|
+
});
|
|
308
|
+
if (typeof authResponse === 'string') {
|
|
309
|
+
authHtml = authResponse;
|
|
310
|
+
}
|
|
311
|
+
else if (authResponse && typeof authResponse === 'object') {
|
|
312
|
+
const respObj = authResponse;
|
|
313
|
+
const respHeaders = respObj.headers;
|
|
314
|
+
if (respHeaders && respHeaders.location) {
|
|
315
|
+
redirectUrl = respHeaders.location;
|
|
316
|
+
}
|
|
317
|
+
authHtml = respObj.body || '';
|
|
318
|
+
}
|
|
267
319
|
}
|
|
268
|
-
else if (
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (
|
|
272
|
-
|
|
320
|
+
else if (stateToken || htmlContent.includes('auth0.com') || htmlContent.includes('/u/login')) {
|
|
321
|
+
// New Auth0-based flow
|
|
322
|
+
// Extract state from the login page URL if not already found
|
|
323
|
+
if (!stateToken) {
|
|
324
|
+
// Try to get state from the response URL or form
|
|
325
|
+
const loginFormMatch = htmlContent.match(/action="([^"]*\/u\/login[^"]*)"/);
|
|
326
|
+
if (loginFormMatch) {
|
|
327
|
+
const formUrl = loginFormMatch[1];
|
|
328
|
+
const formStateMatch = formUrl.match(/state=([^&"]+)/);
|
|
329
|
+
if (formStateMatch) {
|
|
330
|
+
stateToken = decodeURIComponent(formStateMatch[1]);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (!stateToken) {
|
|
335
|
+
// Last resort: extract from any state parameter in the HTML
|
|
336
|
+
const anyStateMatch = htmlContent.match(/state=([a-zA-Z0-9_-]+)/);
|
|
337
|
+
if (anyStateMatch) {
|
|
338
|
+
stateToken = anyStateMatch[1];
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (!stateToken) {
|
|
342
|
+
throw new Error(`Could not extract state token from Auth0 login page. Response preview: ${htmlContent.substring(0, 500)}`);
|
|
343
|
+
}
|
|
344
|
+
// Submit credentials to Auth0 /u/login endpoint
|
|
345
|
+
const loginResponse = await context.helpers.httpRequest({
|
|
346
|
+
method: 'POST',
|
|
347
|
+
url: `https://identity.vwgroup.io/u/login?state=${encodeURIComponent(stateToken)}`,
|
|
348
|
+
headers: {
|
|
349
|
+
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
|
|
350
|
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
351
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
352
|
+
'Origin': 'https://identity.vwgroup.io',
|
|
353
|
+
'Referer': `https://identity.vwgroup.io/u/login?state=${encodeURIComponent(stateToken)}`,
|
|
354
|
+
},
|
|
355
|
+
body: new URLSearchParams({
|
|
356
|
+
state: stateToken,
|
|
357
|
+
username: email,
|
|
358
|
+
password: password,
|
|
359
|
+
action: 'default',
|
|
360
|
+
}).toString(),
|
|
361
|
+
encoding: 'text',
|
|
362
|
+
returnFullResponse: true,
|
|
363
|
+
ignoreHttpStatusErrors: true,
|
|
364
|
+
});
|
|
365
|
+
if (typeof loginResponse === 'string') {
|
|
366
|
+
authHtml = loginResponse;
|
|
273
367
|
}
|
|
274
|
-
|
|
368
|
+
else if (loginResponse && typeof loginResponse === 'object') {
|
|
369
|
+
const respObj = loginResponse;
|
|
370
|
+
const respHeaders = respObj.headers;
|
|
371
|
+
if (respHeaders && respHeaders.location) {
|
|
372
|
+
redirectUrl = respHeaders.location;
|
|
373
|
+
}
|
|
374
|
+
authHtml = respObj.body || '';
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
throw new Error(`Unknown login page format. Response preview: ${htmlContent.substring(0, 500)}`);
|
|
275
379
|
}
|
|
276
380
|
if (!redirectUrl && authHtml) {
|
|
277
381
|
// Check if we got a redirect in the response HTML
|
|
@@ -280,17 +384,35 @@ async function vwLogin(context, email, password) {
|
|
|
280
384
|
redirectUrl = redirectMatch[1];
|
|
281
385
|
}
|
|
282
386
|
}
|
|
283
|
-
// Follow redirects to get the auth code
|
|
387
|
+
// Follow redirects to get the auth code, id_token, and access_token
|
|
284
388
|
let authCode = '';
|
|
389
|
+
let idToken = '';
|
|
390
|
+
let accessToken = '';
|
|
285
391
|
let maxRedirects = 10;
|
|
286
392
|
while (maxRedirects > 0 && redirectUrl && !authCode) {
|
|
393
|
+
// Extract tokens from URL fragment or query params
|
|
394
|
+
// The response_type 'code id_token token' returns all three
|
|
287
395
|
if (redirectUrl.includes('code=')) {
|
|
288
|
-
const codeMatch = redirectUrl.match(/code=([
|
|
396
|
+
const codeMatch = redirectUrl.match(/code=([^&#]+)/);
|
|
289
397
|
if (codeMatch) {
|
|
290
398
|
authCode = codeMatch[1];
|
|
291
|
-
break;
|
|
292
399
|
}
|
|
293
400
|
}
|
|
401
|
+
if (redirectUrl.includes('id_token=')) {
|
|
402
|
+
const idTokenMatch = redirectUrl.match(/id_token=([^&#]+)/);
|
|
403
|
+
if (idTokenMatch) {
|
|
404
|
+
idToken = idTokenMatch[1];
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (redirectUrl.includes('access_token=')) {
|
|
408
|
+
const accessTokenMatch = redirectUrl.match(/access_token=([^&#]+)/);
|
|
409
|
+
if (accessTokenMatch) {
|
|
410
|
+
accessToken = accessTokenMatch[1];
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if (authCode) {
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
294
416
|
const followResponse = await context.helpers.httpRequest({
|
|
295
417
|
method: 'GET',
|
|
296
418
|
url: redirectUrl.startsWith('http') ? redirectUrl : `https://identity.vwgroup.io${redirectUrl}`,
|
|
@@ -320,21 +442,48 @@ async function vwLogin(context, email, password) {
|
|
|
320
442
|
throw new Error('Could not obtain authorization code. Please check your credentials.');
|
|
321
443
|
}
|
|
322
444
|
// Step 4: Exchange auth code for tokens
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
445
|
+
// Try the new CARIAD login endpoint first
|
|
446
|
+
let tokenResponse;
|
|
447
|
+
try {
|
|
448
|
+
const cariadResponse = await context.helpers.httpRequest({
|
|
449
|
+
method: 'POST',
|
|
450
|
+
url: 'https://emea.bff.cariad.digital/user-login/login/v1',
|
|
451
|
+
headers: {
|
|
452
|
+
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
|
|
453
|
+
'Accept': 'application/json',
|
|
454
|
+
'Content-Type': 'application/json',
|
|
455
|
+
},
|
|
456
|
+
body: {
|
|
457
|
+
state: authorizeParams.get('state'),
|
|
458
|
+
id_token: idToken,
|
|
459
|
+
redirect_uri: VW_REDIRECT_URI,
|
|
460
|
+
region: 'emea',
|
|
461
|
+
access_token: accessToken,
|
|
462
|
+
authorizationCode: authCode,
|
|
463
|
+
code_verifier: codeVerifier,
|
|
464
|
+
},
|
|
465
|
+
});
|
|
466
|
+
tokenResponse = cariadResponse;
|
|
467
|
+
}
|
|
468
|
+
catch {
|
|
469
|
+
// Fallback to old token exchange endpoint
|
|
470
|
+
tokenResponse = await context.helpers.httpRequest({
|
|
471
|
+
method: 'POST',
|
|
472
|
+
url: 'https://tokenrefreshservice.apps.emea.vwapps.io/exchangeAuthCode',
|
|
473
|
+
headers: {
|
|
474
|
+
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
|
|
475
|
+
'Accept': 'application/json',
|
|
476
|
+
'Content-Type': 'application/json',
|
|
477
|
+
'X-Client-Id': VW_CLIENT_ID,
|
|
478
|
+
},
|
|
479
|
+
body: {
|
|
480
|
+
auth_code: authCode,
|
|
481
|
+
id_token: idToken || '',
|
|
482
|
+
brand: 'vw',
|
|
483
|
+
code_verifier: codeVerifier,
|
|
484
|
+
},
|
|
485
|
+
});
|
|
486
|
+
}
|
|
338
487
|
return {
|
|
339
488
|
accessToken: tokenResponse.access_token,
|
|
340
489
|
refreshToken: tokenResponse.refresh_token,
|
package/package.json
CHANGED