Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Impossibile to refresh token when access token is expired #194

Open
metalsho opened this issue Feb 11, 2023 · 9 comments
Open

Impossibile to refresh token when access token is expired #194

metalsho opened this issue Feb 11, 2023 · 9 comments

Comments

@metalsho
Copy link

Hi everyone,

I need to make an App with and "everlasting" session.
I can refresh the token (refreshToken) if the App is open and the token is not expired. But if I close the app, and the token expires, when I open the app (or the angular website) every call to auth fails:

  • isAuthenticated$: return false;
  • getValidToken (with or without the buffer): return error
  • loadTokenFromStorage: do nothing
  • refreshToken: do nothing

I tried to change the order of those calls, and wait the result every one of them before try the next, but the results are the same.

I'm waiting for both ready-state of platform and auth service, but it seems that it's impossibile to read the stored token.
I tried even to change the store module. I switched to the IonicStorage (indexedDB on the web, as example) so I am sure that is not a problem related to the volatile nature of the localStorage.

The "funny" part is that I can acktually manage to refresh the session ( and obtain a valid Access Token) if I make the call to the okta endpoint by myself using the httpClient. I tried to "revive" the auth service overwriting the stored response token with the new one, but It seems to be useless: the ionic-appauth service cannot retrieve any valid token anymore.

Can you please give me an example of a working "everlasting" session setup?

Thank you in advance.

@sergiusvet
Copy link

sergiusvet commented Mar 24, 2023

Having the same issue. Did you manage somehow to find a workaround to this?

@metalsho
Copy link
Author

Having the same issue. Did you manage somehow to find a workaround to this?

This is my DIY solution:

const storedToken = await this.tokenService.tokenStore(); // tokenService simply manage the storage for the token

if (!storedToken) {
  return undefined;
}

const url = `${OKTA_HOST_URL}/v1/token`;
const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
const params = new HttpParams()
  .set('grant_type', 'refresh_token')
  .set('client_id', CLIENT_ID)
  .set('refresh_token', storedToken.refresh_token);
const token = await this.http.post<Token>(url, {}, {headers, params}).toPromise();
await this.tokenService.tokenStore('set', token);
await this.auth.loadTokenFromStorage(); // AuthService from ionic-appauth

I hope this will be helpful to you.

@sergiusvet
Copy link

So basically when you override the token which is stored in the localStorage you simply call the .loadTokenFromStorage() method on the Auth instance, did I get it correctly? Because I was playing around with tokens in the localStorage and after changing something there I was just simply kicked out of the session.

@sergiusvet
Copy link

My implementation is based on the vue example coming alongside this repo.

// router/index.ts

router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth) {
    Auth.Instance.initComplete$.pipe(
      filter(complete => complete),
      switchMap(() => Auth.Instance.isAuthenticated$),
      take(1))
        .subscribe((isAuthenticated) => {
            if(isAuthenticated) {
              next();
            }else{
              Auth.tryRefreshingTheToken().then(() => {
                next()
              })
              .catch(() => {
                next('/landing')
              })
            }
        });
  }else{
    next();
  }
})
// AuthService.ts

public static tryRefreshingTheToken() {
    return new Promise((resolve, reject) => {
      const tokenResponse = localStorage.getItem('token_response')
      if (! tokenResponse) reject('No token stored in the storage. Authentication required.')

      const { refresh_token } = JSON.parse(tokenResponse || '')

      if (! refresh_token) reject('No refresh token was found. Authentication required.')

      const url = `${Auth.baseUrl}/connect/token`

      const params = {
        client_id: Auth.clientId,
        redirect_uri: Auth.redirectUrl,
        grant_type: 'refresh_token',
        refresh_token
      }

      fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: new URLSearchParams(params).toString()
      })
        .then(response => response.json())
        .then(async data => {
          localStorage.setItem('token_response', JSON.stringify(data))
          await Auth.Instance.loadTokenFromStorage()
          resolve(data)
        })
        .catch(error => console.error(error));
    })
  }

This fixed the issue of finding the app unauthenticated when the token expires.

@metalsho
Copy link
Author

metalsho commented Mar 25, 2023

So basically when you override the token which is stored in the localStorage you simply call the .loadTokenFromStorage() method on the Auth instance, did I get it correctly? Because I was playing around with tokens in the localStorage and after changing something there I was just simply kicked out of the session.

I suggest to use another storage solution instead of localStorage, because localStorage could be erased by the OS of the mobile device, for example, when it is out of memory.

I not sure that my solution is correct (that's the reason I'm here) but for now seems to work (I'm using Angular):

AppModule

imports:[
  IonicStorageModule.forRoot({
        name: '_ionicstorage',
        // eslint-disable-next-line no-underscore-dangle
        driverOrder: [
          CordovaSQLiteDriver._driver,
          Drivers.IndexedDB,
          Drivers.LocalStorage
        ]
    }),

AuthModule

 providers: [
    {
      provide: StorageBackend,
      useClass: IonicStorage,
    },

@Moataz01210049831
Copy link

Having the same issue. Did you manage somehow to find a workaround to this?

This is my DIY solution:

const storedToken = await this.tokenService.tokenStore(); // tokenService simply manage the storage for the token

if (!storedToken) {
  return undefined;
}

const url = `${OKTA_HOST_URL}/v1/token`;
const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
const params = new HttpParams()
  .set('grant_type', 'refresh_token')
  .set('client_id', CLIENT_ID)
  .set('refresh_token', storedToken.refresh_token);
const token = await this.http.post<Token>(url, {}, {headers, params}).toPromise();
await this.tokenService.tokenStore('set', token);
await this.auth.loadTokenFromStorage(); // AuthService from ionic-appauth

I hope this will be helpful to you.

Could you please tell me where i can but this because i have issue with refreshtoken i got two requests one success and second failed due to refresh token not change

@metalsho
Copy link
Author

Could you please tell me where i can but this because i have issue with refreshtoken i got two requests one success and second failed due to refresh token not change

That is a method that I call instead of the official refreshToken when getValidToken fails to return a valid token.

You can put it wherever you like.

@Moataz01210049831
Copy link

the problem is when token expired , it start automatically calling for new refresh token and make multiaple requests , one success but other failed .
so my question is can i stop refresh token and get it manually ?

@Moataz01210049831
Copy link

and another thing if you don't mind
await this.tokenService.tokenStore(); //

how can i import this "token store" ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants