Skip to content

Fix: Authentication fails with 422 error due to incorrect request body format #4

Description

@romzes5000

Hi! 👋

Firstly, thanks for your work on this project! 🙂

Today I used patch-package to patch @montarist/airalo-api@1.0.4 for the project I'm working on.

The authenticate method in AiraloService fails when attempting to retrieve an access token from the /v2/token endpoint, resulting in a 422 Unprocessable Entity error.

Problem:

The method currently attempts to send the authentication credentials (client_id, client_secret, grant_type) using a FormData object. Debugging showed that when axios sends this request, the actual request body received by the server is effectively empty (data: {} in internal axios config logs), even though the FormData object is populated correctly in the client-side code. This mismatch causes the Airalo API to reject the request with a 422 error because the required fields are missing from the body it parses.

Attempts to manually set the Content-Type: multipart/form-data header resulted in a "Missing boundary" error, indicating further incompatibility with how the server expects the data for this specific endpoint.

Solution:

The /v2/token endpoint appears to expect the credentials either as application/json or application/x-www-form-urlencoded, but not multipart/form-data.

The fix involves changing the authenticate method to pass a plain JavaScript object containing client_id, client_secret, and grant_type as the data payload for the axios.post request, instead of using FormData. This allows axios to correctly serialize the data (likely as application/json or x-www-form-urlencoded by default for plain objects), which the API endpoint successfully processes.

The provided diff implements this change in both the compiled JavaScript (dist/) and the source TypeScript (src/) files, resolving the authentication failure.

Here is the diff that solved my problem:

diff --git a/node_modules/@montarist/airalo-api/dist/services/airalo.service.js b/node_modules/@montarist/airalo-api/dist/services/airalo.service.js
index 7e70be0..1f18a5e 100644
--- a/node_modules/@montarist/airalo-api/dist/services/airalo.service.js
+++ b/node_modules/@montarist/airalo-api/dist/services/airalo.service.js
@@ -55,11 +55,11 @@ class AiraloService {
         }
     }
     async authenticate() {
-        const formData = new FormData();
-        formData.append('client_id', this.config.clientId);
-        formData.append('client_secret', this.config.clientSecret);
-        formData.append('grant_type', 'client_credentials');
-        const response = await this.handleRequest(() => this.axiosInstance.post('/v2/token', formData));
+        const response = await this.handleRequest(() => this.axiosInstance.post('/v2/token', {
+            client_id: this.config.clientId,
+            client_secret: this.config.clientSecret,
+            grant_type: 'client_credentials'
+        }));
         this.accessToken = response.data.access_token;
     }
     async getOrders(params) {
diff --git a/node_modules/@montarist/airalo-api/src/services/airalo.service.ts b/node_modules/@montarist/airalo-api/src/services/airalo.service.ts
index 5e61442..9929ba2 100644
--- a/node_modules/@montarist/airalo-api/src/services/airalo.service.ts
+++ b/node_modules/@montarist/airalo-api/src/services/airalo.service.ts
@@ -137,13 +137,12 @@ export class AiraloService {
      * @throws {AiraloError} If authentication fails
      */
     async authenticate(): Promise<void> {
-        const formData = new FormData();
-        formData.append('client_id', this.config.clientId);
-        formData.append('client_secret', this.config.clientSecret);
-        formData.append('grant_type', 'client_credentials');
-
         const response = await this.handleRequest<AiraloAuthResponse>(() =>
-            this.axiosInstance.post('/v2/token', formData),
+            this.axiosInstance.post('/v2/token', {
+                client_id: this.config.clientId,
+                client_secret: this.config.clientSecret,
+                grant_type: 'client_credentials'
+            }),
         );
 
         this.accessToken = response.data.access_token;

This issue body was partially generated by patch-package.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions