supertokens / supertokens-auth-react

ReactJS authentication module for SuperTokens

Home Page:https://supertokens.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[error] - Unhandled Promise rejection: Please provide a valid domain name ; Zone: <root> ; Task: Promise.then ; Value: {}

cvishalc opened this issue · comments

Hello,

I'm facing an issue with Ionic6 iOS. After successful authentication, this POST /auth/session/refresh request is called continuously in loop automatically. And this thing is working perfectly in Ionic6 Android.

Error logs:
[error] - Unhandled Promise rejection: Please provide a valid domain name ; Zone: <root> ; Task: Promise.then ; Value: {} T@capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:555342 F@capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:555571 h@capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:570751 l@capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:572891 @capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:532300 De@capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:527094 @capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:526037 l@capacitor://localhost/polyfills.3ebd5e0cff18d293.js:1:18807 @capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:525751 @capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:561117 D@capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:560604 @capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:559620 l@capacitor://localhost/polyfills.3ebd5e0cff18d293.js:1:18807 @capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:559370 @capacitor://localhost/8372.9f0347155041a7b1.js:1:21570 loadIcon@capacitor://localhost/8372.9f0347155041a7b1.js:1:22054 @capacitor://localhost/8372.9f0347155041a7b1.js:1:20728 waitUntilVisible@capacitor://localhost/8372.9f0347155041a7b1.js:1:21034 connectedCallback@capacitor://localhost/8372.9f0347155041a7b1.js:1:20676 On@capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:117763 Ge@capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:122050 @capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:121648 generatorResume@[native code] r@capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:923370 f@capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:923573 @capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:923632 l@capacitor://localhost/polyfills.3ebd5e0cff18d293.js:1:18807 @capacitor://localhost/main.38b8ccfc0b14c5e7.js:1:923524

Hey @cvishalc,

I set up a basic ionic app and ran it on iOS and did not face any errors, if possible please provide a minimal sample to reproduce the issue

The error stack you have provided doesn't match the claim that "POST /auth/session/refresh request is called continuously in loop automatically".

Please provide more details about the error. Closing this issue for now.

Hey @cvishalc,

I set up a basic ionic app and ran it on iOS and did not face any errors, if possible please provide a minimal sample to reproduce the issue

@nkshah2 Have you tried with ionic 6 capacitor 3.6.0 in ios ?

@cvishalc Yes, ionic 6 and capacitor 3.6.0 works fine as well

@nkshah2

Sorry for the late response, you are absolutely correct we can also login successfully but when I call the get API with 'axios' example:-

import axios from "axios";
import { addAxiosInterceptors } from 'supertokens-website';
async getDate(){
const response = await axios.get(this.auth.getURL + /import?empty=${importBool}, { withCredentials: true })
return response.data
}

when this above function is called the request goes into the loop.

Secondly,
First time the Login is executed successfully and when I close the application and reopen It at that time, the request goes into the loop.

the example of code is, please let me know if there is any mistake.

import { Component } from '@angular/core';
import SuperTokens from 'supertokens-web-js';
import Session from 'supertokens-web-js/recipe/session';
import EmailPassword from 'supertokens-web-js/recipe/emailpassword'
import { splitCookiesString, parse as parseSetCookieString } from "set-cookie-parser"

addCustomInterceptorsToGlobalFetch();

SuperTokens.init({
  appInfo: {
    apiDomain: 'http://192.168.29.128:8080',
    apiBasePath: "/auth",
    appName: "Commercial",
  },
  recipeList: [
    Session.init({
      override: {
        functions: (oI) => {
          return {
            ...oI,
            // this override is only required if you are using axios
            addAxiosInterceptors: function (input) {
              addCustomInterceptosToAxios(input);
              return oI.addAxiosInterceptors(input);
            },
            signOut: async function (input) {
              console.log("input", input)
              await oI.signOut(input);
              localStorage.removeItem("st-cookie");
            },
          };
        },
      },
    }),
    EmailPassword.init(),
  ],
});
@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss'],
})
export class AppComponent {

  constructor(private platform: Platform) {
    this.initializeApp()
  }
 initializeApp() {
    this.platform.ready().then(() => {
        if (await Session.doesSessionExist()) {

         }else{

         }
     });
}

export function addCustomInterceptorsToGlobalFetch() {
  const origFetch = window.fetch;
  window.fetch = async (input: any, init) => {
    // Check if the we need to add the cookies
    if (isApiDomain(input.url || input)) {
      // Simply add the stored string into a header, it's already in the correct format.
      const stCookies = localStorage.getItem("st-cookie");
      if (stCookies) {
        const headers = new Headers(init?.headers);
        headers.append("st-cookie", stCookies);
        init = {
          ...init,
          headers,
        };
      }
    }

    const res = await origFetch(input, init);

    // Check if the we need to process the cookies in the response
    if (isApiDomain(input.url || input)) {
      const respCookies = res.headers.get("st-cookie");
      setCookiesInLocalstorage(respCookies);
    }
    return res;
  };
}

export function addCustomInterceptosToAxios(input: { axiosInstance: any; userContext: any }) {
  input.axiosInstance.interceptors.request.use(
    function (config: any) {
      // Check if the we need to add the cookies
      if (isApiDomain(config.url)) {
        const stCookies = localStorage.getItem("st-cookie");
        if (stCookies) {
          // Simply add the stored string into a header, it's already in the correct format.
          config.headers["st-cookie"] = stCookies;
        }
      }
      return config;
    },
    function (error: any) {
      return Promise.reject(error);
    }
  );

  input.axiosInstance.interceptors.response.use(
    function (res: any) {
      // Check if the we need to process the cookies in the response
      if (isApiDomain(res.config.url)) {
        const respCookies = res.headers["st-cookie"];

        setCookiesInLocalstorage(respCookies);
      }
      return res;
    },
    // We need to process error responses as well
    function (error: any) {
      // Check if the we need to process the cookies in the response
      if (isApiDomain(error.config.url)) {
        const res = error.response;
        const respCookies = res.headers["st-cookie"];

        setCookiesInLocalstorage(respCookies);
      }
      return Promise.reject(error);
    }
  );
}

// helper function to store cookie string correctly in localstorage
function setCookiesInLocalstorage(respCookies: any) {
  if (respCookies) {
    // Split and parse cookies received
    const respCookieMap: any = parseSetCookieString(splitCookiesString(respCookies), { decodeValues: false, map: true });

    // Check if we have anything stored already
    const localstorageCookies = localStorage.getItem("st-cookie");
    if (localstorageCookies !== null) {
      // Split and parse cookies we have in stored previously
      const splitStoredCookies = localstorageCookies.split("; ").map((cookie) => cookie.split("="));

      for (const [name, value] of splitStoredCookies) {
        // Keep old cookies if they weren't overwritten
        if (respCookieMap[name] === undefined) {
          respCookieMap[name] = { name, value };
        }
      }
    }

    // Save the combined cookies in a the format of a Cookie header
    // Please keep in mind that these have no expiration and lack many of the things done automatically for cookies
    // Many of these features can be implemented, but they are out of scope for this example
    localStorage.setItem(
      "st-cookie",
      Object.values(respCookieMap)
        .map((cookie: any) => `${cookie.name}=${cookie.value}`)
        .join("; ")
    );
  }
}

function isApiDomain(str: string) {
  return str.startsWith(getApiDomain());
}

export function getApiDomain() {
  return 'http://192.168.29.128:8080';
}

A couple things:

  • addAxiosInterceptors should be imported from supertokens-web-js/recipe/session
  • When using axios you also have to call addAxiosInterceptors after calling addCustomInterceptorsToGlobalFetch

I have done changes as per your comment but that did not help.

I have attached the code, please let me know if anything else is required.

Service file

import axios from "axios";
import Session from "supertokens-auth-react/recipe/session";
Session.addAxiosInterceptors(axios);

@Injectable({
  providedIn: 'root'
})
export class SyncDataService {
  constructor() { }

  public async requestFromSyncNetwork(importBool) {
    try {
      const response = await axios.get(this.auth.getURL + `/import?empty=${importBool}`, { withCredentials: true })
      return response.data
    } catch (error) {
      console.log(error)
    }
}

App components

import { Component } from '@angular/core';
import SuperTokens from 'supertokens-web-js';
import Session from 'supertokens-web-js/recipe/session';
import EmailPassword from 'supertokens-web-js/recipe/emailpassword'
import { splitCookiesString, parse as parseSetCookieString } from "set-cookie-parser"

addCustomInterceptorsToGlobalFetch();
Session.addAxiosInterceptors(axios);

SuperTokens.init({
  appInfo: {
    apiDomain: 'http://192.168.29.128:8080',
    apiBasePath: "/auth",
    appName: "Commercial",
  },
  recipeList: [
    Session.init({
      override: {
        functions: (oI) => {
          return {
            ...oI,
            // this override is only required if you are using axios
            addAxiosInterceptors: function (input) {
              addCustomInterceptosToAxios(input);
              return oI.addAxiosInterceptors(input);
            },
            signOut: async function (input) {
              console.log("input", input)
              await oI.signOut(input);
              localStorage.removeItem("st-cookie");
            },
          };
        },
      },
    }),
    EmailPassword.init(),
  ],
});
@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss'],
})
export class AppComponent {

  constructor(private platform: Platform) {
    this.initializeApp()
  }
 initializeApp() {
    this.platform.ready().then(() => {
        if (await Session.doesSessionExist()) {

         }else{

         }
     });
}

export function addCustomInterceptorsToGlobalFetch() {
  const origFetch = window.fetch;
  window.fetch = async (input: any, init) => {
    // Check if the we need to add the cookies
    if (isApiDomain(input.url || input)) {
      // Simply add the stored string into a header, it's already in the correct format.
      const stCookies = localStorage.getItem("st-cookie");
      if (stCookies) {
        const headers = new Headers(init?.headers);
        headers.append("st-cookie", stCookies);
        init = {
          ...init,
          headers,
        };
      }
    }

    const res = await origFetch(input, init);

    // Check if the we need to process the cookies in the response
    if (isApiDomain(input.url || input)) {
      const respCookies = res.headers.get("st-cookie");
      setCookiesInLocalstorage(respCookies);
    }
    return res;
  };
}

export function addCustomInterceptosToAxios(input: { axiosInstance: any; userContext: any }) {
  input.axiosInstance.interceptors.request.use(
    function (config: any) {
      // Check if the we need to add the cookies
      if (isApiDomain(config.url)) {
        const stCookies = localStorage.getItem("st-cookie");
        if (stCookies) {
          // Simply add the stored string into a header, it's already in the correct format.
          config.headers["st-cookie"] = stCookies;
        }
      }
      return config;
    },
    function (error: any) {
      return Promise.reject(error);
    }
  );

  input.axiosInstance.interceptors.response.use(
    function (res: any) {
      // Check if the we need to process the cookies in the response
      if (isApiDomain(res.config.url)) {
        const respCookies = res.headers["st-cookie"];

        setCookiesInLocalstorage(respCookies);
      }
      return res;
    },
    // We need to process error responses as well
    function (error: any) {
      // Check if the we need to process the cookies in the response
      if (isApiDomain(error.config.url)) {
        const res = error.response;
        const respCookies = res.headers["st-cookie"];

        setCookiesInLocalstorage(respCookies);
      }
      return Promise.reject(error);
    }
  );
}

// helper function to store cookie string correctly in localstorage
function setCookiesInLocalstorage(respCookies: any) {
  if (respCookies) {
    // Split and parse cookies received
    const respCookieMap: any = parseSetCookieString(splitCookiesString(respCookies), { decodeValues: false, map: true });

    // Check if we have anything stored already
    const localstorageCookies = localStorage.getItem("st-cookie");
    if (localstorageCookies !== null) {
      // Split and parse cookies we have in stored previously
      const splitStoredCookies = localstorageCookies.split("; ").map((cookie) => cookie.split("="));

      for (const [name, value] of splitStoredCookies) {
        // Keep old cookies if they weren't overwritten
        if (respCookieMap[name] === undefined) {
          respCookieMap[name] = { name, value };
        }
      }
    }

    // Save the combined cookies in a the format of a Cookie header
    // Please keep in mind that these have no expiration and lack many of the things done automatically for cookies
    // Many of these features can be implemented, but they are out of scope for this example
    localStorage.setItem(
      "st-cookie",
      Object.values(respCookieMap)
        .map((cookie: any) => `${cookie.name}=${cookie.value}`)
        .join("; ")
    );
  }
}

function isApiDomain(str: string) {
  return str.startsWith(getApiDomain());
}

export function getApiDomain() {
  return 'http://192.168.29.128:8080';
}

Reopening this issue @nkshah2