n8n-nodes-jygse-vw-weconnect 0.1.2 → 0.1.3

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,42 @@ class VwWeConnect {
141
141
  }
142
142
  }
143
143
  exports.VwWeConnect = VwWeConnect;
144
- // VW OAuth2 Configuration
145
- const VW_CLIENT_ID = '9496332b-ea03-4091-a224-8c746b885068@apps_vw-dilab_com';
146
- const VW_SCOPE = 'openid profile mbb';
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 {
166
+ // Generate PKCE values
167
+ const codeVerifier = generateCodeVerifier();
168
+ const codeChallenge = await generateCodeChallenge(codeVerifier);
150
169
  // Step 1: Get authorization page and extract form data
151
170
  const authorizeUrl = 'https://identity.vwgroup.io/oidc/v1/authorize';
152
171
  const authorizeParams = new URLSearchParams({
153
172
  client_id: VW_CLIENT_ID,
154
173
  scope: VW_SCOPE,
155
- response_type: 'code',
174
+ response_type: VW_RESPONSE_TYPE,
156
175
  redirect_uri: VW_REDIRECT_URI,
157
176
  nonce: generateNonce(),
158
177
  state: generateNonce(),
178
+ code_challenge: codeChallenge,
179
+ code_challenge_method: 'plain',
159
180
  });
160
181
  const authorizeResponse = await context.helpers.httpRequest({
161
182
  method: 'GET',
@@ -280,17 +301,35 @@ async function vwLogin(context, email, password) {
280
301
  redirectUrl = redirectMatch[1];
281
302
  }
282
303
  }
283
- // Follow redirects to get the auth code
304
+ // Follow redirects to get the auth code, id_token, and access_token
284
305
  let authCode = '';
306
+ let idToken = '';
307
+ let accessToken = '';
285
308
  let maxRedirects = 10;
286
309
  while (maxRedirects > 0 && redirectUrl && !authCode) {
310
+ // Extract tokens from URL fragment or query params
311
+ // The response_type 'code id_token token' returns all three
287
312
  if (redirectUrl.includes('code=')) {
288
- const codeMatch = redirectUrl.match(/code=([^&]+)/);
313
+ const codeMatch = redirectUrl.match(/code=([^&#]+)/);
289
314
  if (codeMatch) {
290
315
  authCode = codeMatch[1];
291
- break;
292
316
  }
293
317
  }
318
+ if (redirectUrl.includes('id_token=')) {
319
+ const idTokenMatch = redirectUrl.match(/id_token=([^&#]+)/);
320
+ if (idTokenMatch) {
321
+ idToken = idTokenMatch[1];
322
+ }
323
+ }
324
+ if (redirectUrl.includes('access_token=')) {
325
+ const accessTokenMatch = redirectUrl.match(/access_token=([^&#]+)/);
326
+ if (accessTokenMatch) {
327
+ accessToken = accessTokenMatch[1];
328
+ }
329
+ }
330
+ if (authCode) {
331
+ break;
332
+ }
294
333
  const followResponse = await context.helpers.httpRequest({
295
334
  method: 'GET',
296
335
  url: redirectUrl.startsWith('http') ? redirectUrl : `https://identity.vwgroup.io${redirectUrl}`,
@@ -320,21 +359,48 @@ async function vwLogin(context, email, password) {
320
359
  throw new Error('Could not obtain authorization code. Please check your credentials.');
321
360
  }
322
361
  // Step 4: Exchange auth code for tokens
323
- const tokenResponse = await context.helpers.httpRequest({
324
- method: 'POST',
325
- url: 'https://tokenrefreshservice.apps.emea.vwapps.io/exchangeAuthCode',
326
- headers: {
327
- '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',
328
- 'Accept': 'application/json',
329
- 'Content-Type': 'application/json',
330
- 'X-Client-Id': VW_CLIENT_ID,
331
- },
332
- body: {
333
- auth_code: authCode,
334
- id_token: '',
335
- brand: 'vw',
336
- },
337
- });
362
+ // Try the new CARIAD login endpoint first
363
+ let tokenResponse;
364
+ try {
365
+ const cariadResponse = await context.helpers.httpRequest({
366
+ method: 'POST',
367
+ url: 'https://emea.bff.cariad.digital/user-login/login/v1',
368
+ headers: {
369
+ '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',
370
+ 'Accept': 'application/json',
371
+ 'Content-Type': 'application/json',
372
+ },
373
+ body: {
374
+ state: authorizeParams.get('state'),
375
+ id_token: idToken,
376
+ redirect_uri: VW_REDIRECT_URI,
377
+ region: 'emea',
378
+ access_token: accessToken,
379
+ authorizationCode: authCode,
380
+ code_verifier: codeVerifier,
381
+ },
382
+ });
383
+ tokenResponse = cariadResponse;
384
+ }
385
+ catch {
386
+ // Fallback to old token exchange endpoint
387
+ tokenResponse = await context.helpers.httpRequest({
388
+ method: 'POST',
389
+ url: 'https://tokenrefreshservice.apps.emea.vwapps.io/exchangeAuthCode',
390
+ headers: {
391
+ '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',
392
+ 'Accept': 'application/json',
393
+ 'Content-Type': 'application/json',
394
+ 'X-Client-Id': VW_CLIENT_ID,
395
+ },
396
+ body: {
397
+ auth_code: authCode,
398
+ id_token: idToken || '',
399
+ brand: 'vw',
400
+ code_verifier: codeVerifier,
401
+ },
402
+ });
403
+ }
338
404
  return {
339
405
  accessToken: tokenResponse.access_token,
340
406
  refreshToken: tokenResponse.refresh_token,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-jygse-vw-weconnect",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "n8n community node for VW We Connect - Control your Volkswagen T6.1 and other VW vehicles",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",