n8n-nodes-jygse-vw-weconnect 0.1.9 → 0.1.11

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.
@@ -146,6 +146,19 @@ const VW_CLIENT_ID = 'a24fba63-34b3-4d43-b181-942111e6bda8@apps_vw-dilab_com';
146
146
  const VW_SCOPE = 'openid profile badge cars dealers vin';
147
147
  const VW_REDIRECT_URI = 'weconnect://authenticated';
148
148
  const VW_RESPONSE_TYPE = 'code id_token token';
149
+ // WeConnect App User-Agent and headers (critical for authentication)
150
+ // Using exact version from WeConnect-python
151
+ const VW_USER_AGENT = 'Volkswagen/3.51.1-android/14';
152
+ const VW_APP_PACKAGE = 'com.volkswagen.weconnect';
153
+ const VW_ACCEPT_LANGUAGE = 'de-de';
154
+ function generateTraceId() {
155
+ // Generate UUID v4 format
156
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
157
+ const r = Math.random() * 16 | 0;
158
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
159
+ return v.toString(16);
160
+ });
161
+ }
149
162
  // Generate PKCE code verifier and challenge
150
163
  function generateCodeVerifier() {
151
164
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
@@ -163,29 +176,28 @@ async function generateCodeChallenge(verifier) {
163
176
  }
164
177
  async function vwLogin(context, email, password) {
165
178
  try {
166
- // Generate PKCE values
167
- const codeVerifier = generateCodeVerifier();
168
- const codeChallenge = await generateCodeChallenge(codeVerifier);
169
- const stateParam = generateNonce();
170
- // Step 1: Get authorization page via CARIAD BFF (WeConnect-python approach)
179
+ const traceId = generateTraceId();
180
+ const nonce = generateNonce();
181
+ // Common headers used for all requests (matching WeConnect-python exactly)
182
+ const commonHeaders = {
183
+ 'User-Agent': VW_USER_AGENT,
184
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
185
+ 'Accept-Language': VW_ACCEPT_LANGUAGE,
186
+ 'Cache-Control': 'no-cache',
187
+ 'x-android-package-name': VW_APP_PACKAGE,
188
+ 'weconnect-trace-id': traceId,
189
+ };
190
+ // Step 1: Get authorization page via CARIAD BFF
191
+ // WeConnect-python only sends redirect_uri and nonce to this endpoint
171
192
  const authorizeUrl = 'https://emea.bff.cariad.digital/user-login/v1/authorize';
172
193
  const authorizeParams = new URLSearchParams({
173
- client_id: VW_CLIENT_ID,
174
- scope: VW_SCOPE,
175
- response_type: VW_RESPONSE_TYPE,
176
194
  redirect_uri: VW_REDIRECT_URI,
177
- nonce: generateNonce(),
178
- state: stateParam,
179
- code_challenge: codeChallenge,
180
- code_challenge_method: 'plain',
195
+ nonce: nonce,
181
196
  });
182
197
  const authorizeResponse = await context.helpers.httpRequest({
183
198
  method: 'GET',
184
199
  url: `${authorizeUrl}?${authorizeParams.toString()}`,
185
- headers: {
186
- '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',
187
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
188
- },
200
+ headers: commonHeaders,
189
201
  encoding: 'text',
190
202
  returnFullResponse: true,
191
203
  ignoreHttpStatusErrors: true,
@@ -238,10 +250,7 @@ async function vwLogin(context, email, password) {
238
250
  const followResponse = await context.helpers.httpRequest({
239
251
  method: 'GET',
240
252
  url: followUrl,
241
- headers: {
242
- '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',
243
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
244
- },
253
+ headers: commonHeaders,
245
254
  encoding: 'text',
246
255
  returnFullResponse: true,
247
256
  ignoreHttpStatusErrors: true,
@@ -347,7 +356,7 @@ async function vwLogin(context, email, password) {
347
356
  method: 'POST',
348
357
  url: 'https://identity.vwgroup.io/signin-service/v1/signin/login/identifier',
349
358
  headers: {
350
- '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',
359
+ 'User-Agent': VW_USER_AGENT,
351
360
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
352
361
  'Content-Type': 'application/x-www-form-urlencoded',
353
362
  },
@@ -383,7 +392,7 @@ async function vwLogin(context, email, password) {
383
392
  method: 'POST',
384
393
  url: 'https://identity.vwgroup.io/signin-service/v1/signin/login/authenticate',
385
394
  headers: {
386
- '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',
395
+ 'User-Agent': VW_USER_AGENT,
387
396
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
388
397
  'Content-Type': 'application/x-www-form-urlencoded',
389
398
  },
@@ -444,8 +453,7 @@ async function vwLogin(context, email, password) {
444
453
  method: 'POST',
445
454
  url: `https://identity.vwgroup.io/u/login?state=${encodeURIComponent(stateToken)}`,
446
455
  headers: {
447
- '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',
448
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
456
+ ...commonHeaders,
449
457
  'Content-Type': 'application/x-www-form-urlencoded',
450
458
  'Origin': 'https://identity.vwgroup.io',
451
459
  'Referer': `https://identity.vwgroup.io/u/login?state=${encodeURIComponent(stateToken)}`,
@@ -523,9 +531,7 @@ async function vwLogin(context, email, password) {
523
531
  const followResponse = await context.helpers.httpRequest({
524
532
  method: 'GET',
525
533
  url: redirectUrl.startsWith('http') ? redirectUrl : `https://identity.vwgroup.io${redirectUrl}`,
526
- headers: {
527
- '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',
528
- },
534
+ headers: commonHeaders,
529
535
  encoding: 'text',
530
536
  returnFullResponse: true,
531
537
  ignoreHttpStatusErrors: true,
@@ -558,28 +564,30 @@ async function vwLogin(context, email, password) {
558
564
  maxRedirects--;
559
565
  }
560
566
  if (!authCode) {
561
- throw new Error(`Could not obtain authorization code. Last redirect: ${redirectUrl || 'none'}. Please check your credentials.`);
567
+ throw new Error(`Could not obtain authorization code. Last redirect: ${redirectUrl || 'none'}. Auth HTML preview: ${authHtml.substring(0, 500)}`);
562
568
  }
563
- // Step 4: Exchange auth code for tokens
564
- // Try the new CARIAD login endpoint first
569
+ // Step 4: Exchange auth code for tokens via CARIAD login endpoint
570
+ // The state parameter should come from the authorize response, not our generated one
565
571
  let tokenResponse;
566
572
  try {
567
573
  const cariadResponse = await context.helpers.httpRequest({
568
574
  method: 'POST',
569
575
  url: 'https://emea.bff.cariad.digital/user-login/login/v1',
570
576
  headers: {
571
- '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',
577
+ 'User-Agent': VW_USER_AGENT,
572
578
  'Accept': 'application/json',
579
+ 'Accept-Language': VW_ACCEPT_LANGUAGE,
573
580
  'Content-Type': 'application/json',
581
+ 'x-android-package-name': VW_APP_PACKAGE,
582
+ 'weconnect-trace-id': traceId,
574
583
  },
575
584
  body: {
576
- state: authorizeParams.get('state'),
585
+ state: stateToken,
577
586
  id_token: idToken,
578
587
  redirect_uri: VW_REDIRECT_URI,
579
588
  region: 'emea',
580
589
  access_token: accessToken,
581
590
  authorizationCode: authCode,
582
- code_verifier: codeVerifier,
583
591
  },
584
592
  });
585
593
  tokenResponse = cariadResponse;
@@ -590,8 +598,9 @@ async function vwLogin(context, email, password) {
590
598
  method: 'POST',
591
599
  url: 'https://tokenrefreshservice.apps.emea.vwapps.io/exchangeAuthCode',
592
600
  headers: {
593
- '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',
601
+ 'User-Agent': VW_USER_AGENT,
594
602
  'Accept': 'application/json',
603
+ 'Accept-Language': VW_ACCEPT_LANGUAGE,
595
604
  'Content-Type': 'application/json',
596
605
  'X-Client-Id': VW_CLIENT_ID,
597
606
  },
@@ -599,7 +608,6 @@ async function vwLogin(context, email, password) {
599
608
  auth_code: authCode,
600
609
  id_token: idToken || '',
601
610
  brand: 'vw',
602
- code_verifier: codeVerifier,
603
611
  },
604
612
  });
605
613
  }
@@ -632,7 +640,7 @@ async function getHomeRegion(context, session, vin) {
632
640
  method: 'GET',
633
641
  url: `https://mal-1a.prd.ece.vwg-connect.com/api/cs/vds/v1/vehicles/${vin}/homeRegion`,
634
642
  headers: {
635
- 'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36',
643
+ 'User-Agent': VW_USER_AGENT,
636
644
  'Accept': 'application/json',
637
645
  'Authorization': `Bearer ${session.accessToken}`,
638
646
  },
@@ -655,7 +663,7 @@ async function getPosition(context, session, vin) {
655
663
  method: 'GET',
656
664
  url: `https://emea.bff.cariad.digital/vehicle/v1/vehicles/${vin}/parkingposition`,
657
665
  headers: {
658
- 'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36',
666
+ 'User-Agent': VW_USER_AGENT,
659
667
  'Accept': 'application/json',
660
668
  'Authorization': `Bearer ${session.accessToken}`,
661
669
  },
@@ -675,7 +683,7 @@ async function getPosition(context, session, vin) {
675
683
  method: 'GET',
676
684
  url: `${homeRegion}/api/bs/cf/v1/VW/DE/vehicles/${vin}/position`,
677
685
  headers: {
678
- 'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36',
686
+ 'User-Agent': VW_USER_AGENT,
679
687
  'Accept': 'application/json',
680
688
  'Authorization': `Bearer ${session.accessToken}`,
681
689
  },
@@ -702,7 +710,7 @@ async function getVehicleStatus(context, session, vin) {
702
710
  method: 'GET',
703
711
  url: `https://emea.bff.cariad.digital/vehicle/v1/vehicles/${vin}/selectivestatus?jobs=all`,
704
712
  headers: {
705
- 'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36',
713
+ 'User-Agent': VW_USER_AGENT,
706
714
  'Accept': 'application/json',
707
715
  'Authorization': `Bearer ${session.accessToken}`,
708
716
  },
@@ -722,7 +730,7 @@ async function getVehicleStatus(context, session, vin) {
722
730
  method: 'GET',
723
731
  url: `${homeRegion}/api/bs/vsr/v1/VW/DE/vehicles/${vin}/status`,
724
732
  headers: {
725
- 'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36',
733
+ 'User-Agent': VW_USER_AGENT,
726
734
  'Accept': 'application/json',
727
735
  'Authorization': `Bearer ${session.accessToken}`,
728
736
  },
@@ -749,7 +757,7 @@ async function getHeaterStatus(context, session, vin) {
749
757
  method: 'GET',
750
758
  url: `${homeRegion}/api/bs/climatisation/v1/VW/DE/vehicles/${vin}/climater`,
751
759
  headers: {
752
- 'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36',
760
+ 'User-Agent': VW_USER_AGENT,
753
761
  'Accept': 'application/json',
754
762
  'Authorization': `Bearer ${session.accessToken}`,
755
763
  },
@@ -776,7 +784,7 @@ async function controlHeater(context, session, vin, spin, action, duration) {
776
784
  method: 'GET',
777
785
  url: `${homeRegion}/api/rolesrights/authorization/v2/vehicles/${vin}/services/rclima_v1/operations/P_START_CLIMA_AU/security-pin-auth-requested`,
778
786
  headers: {
779
- 'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36',
787
+ 'User-Agent': VW_USER_AGENT,
780
788
  'Accept': 'application/json',
781
789
  'Authorization': `Bearer ${session.accessToken}`,
782
790
  },
@@ -789,7 +797,7 @@ async function controlHeater(context, session, vin, spin, action, duration) {
789
797
  method: 'POST',
790
798
  url: `${homeRegion}/api/rolesrights/authorization/v2/security-pin-auth-completed`,
791
799
  headers: {
792
- 'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36',
800
+ 'User-Agent': VW_USER_AGENT,
793
801
  'Accept': 'application/json',
794
802
  'Content-Type': 'application/json',
795
803
  'Authorization': `Bearer ${session.accessToken}`,
@@ -820,7 +828,7 @@ async function controlHeater(context, session, vin, spin, action, duration) {
820
828
  };
821
829
  }
822
830
  const headers = {
823
- 'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36',
831
+ 'User-Agent': VW_USER_AGENT,
824
832
  'Accept': 'application/json',
825
833
  'Content-Type': 'application/json',
826
834
  'Authorization': `Bearer ${session.accessToken}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-jygse-vw-weconnect",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
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",