Remember the logged in user fail

Idea
You only have to log in once and it’s saved on storage. Only if you log out the storage cleaned.

I’m using Capacitor Secure Storage to store the token of the logged-in user to save it so that the user doesn’t have to login every time the RAM is cleaned. It’s not working as I would want it to.

I think it does save the token but doesn’t use it correctly to check if the user is logged or not.
Here’s my code. Only for testing.

service

const helper = new JwtHelperService();

const { SecureStoragePlugin } = Plugins;
const TOKEN_KEY = 'jwt-token';

 
@Injectable({
  providedIn: 'root'
})
export class AuthService {
  public user: Observable<any>;
  private userData = new BehaviorSubject(null);

  constructor(private http: HttpClient, private plt: Platform, private router: Router) { 
    this.loadStoredToken();  
  }

  loadStoredToken() {
    let platformObs = from(this.plt.ready());
 
    this.user = platformObs.pipe(
      switchMap(() => {
        return from(SecureStoragePlugin.get({key:TOKEN_KEY}));
      }),
      map(token => {
        alert(token.value);
        if (token) {
          let decoded = helper.decodeToken(token.value); 
          this.userData.next(decoded);
          return true;
        } else {
          return null;
        }
      })
    );
  }
 
  login(credentials: {email: string, pw: string }) {
    // Normally make a POST request to your APi with your login credentials
    if (credentials.email != 'aa@myemail.com' || credentials.pw != '123') {
      return of(null);
    }
 
    return this.http.get('https://randomuser.me/api/').pipe(
      take(1),
      map(res => {
        //Random jwt token
        return `eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE1Njc2NjU3MDYsImV4cCI6MTU5OTIwMTcwNiwiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoiMTIzNDUiLCJmaXJzdF9uYW1lIjoiU2ltb24iLCJsYXN0X25hbWUiOiJHcmltbSIsImVtYWlsIjoic2FpbW9uQGRldmRhY3RpYy5jb20ifQ.4LZTaUxsX2oXpWN6nrSScFXeBNZVEyuPxcOkbbDVZ5U`;
      }),
      switchMap(token => {
        let decoded = helper.decodeToken(token);
        this.userData.next(decoded);
 
        let storageObs = SecureStoragePlugin.set({key: TOKEN_KEY, value: token });
        return storageObs;
      })
    );
  }
 
  getUser() {
    return this.userData.getValue();
  }
 
  logout() {
    SecureStoragePlugin.remove({ key: TOKEN_KEY}).then(() => {
      this.router.navigateByUrl('/');
      this.userData.next(null);
    });
  }

login.ts

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../services/auth.service';
import { AlertController } from '@ionic/angular';
import { Router } from '@angular/router';
 
@Component({
  selector: 'app-login',
  templateUrl: './login.page.html',
  styleUrls: ['./login.page.scss']
})
export class LoginPage implements OnInit {
  
  credentials = {
    email: 'aa@myemail.com',
    pw: '123'
  };
 
  constructor(
    private auth: AuthService,
    private router: Router,
    private alertCtrl: AlertController
  ) {}
 
  ngOnInit() {}
 
  login() {
    this.auth.login(this.credentials).subscribe(async res => {
      if (res) {
        this.router.navigateByUrl('/members');
      } else {
        const alert = await this.alertCtrl.create({
          header: 'Login Failed',
          message: 'Wrong credentials.',
          buttons: ['OK']
        });
        await alert.present();
      }
    });
  }
}

guard

export class AuthGuard implements CanActivate{
  constructor(private router: Router, private auth: AuthService, private alertCtrl: AlertController) { }
 
  canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
    return this.auth.user.pipe(
      take(1),
      map(user => {
        if (!user) {
          this.alertCtrl.create({
            header: 'Unauthorized',
            message: 'You are not allowed to access that page.',
            buttons: ['OK']
          }).then(alert => alert.present());
 
          this.router.navigateByUrl('/');
          return false;
        } else {
          return true;
        }
      })
    )
  }
}

app-routing.module.ts

import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
import { AuthGuard } from './guards/auth.guard';

const routes: Routes = [
  {
    path: 'members',
    loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule),
    canActivate: [AuthGuard]
  },
  {
    path: '',
    loadChildren: () => import('./login/login.module').then( m => m.LoginPageModule)
  },
  {
    path: 'register',
    loadChildren: () => import('./register/register.module').then( m => m.RegisterPageModule)
  }
];
@NgModule({
  imports: [
    RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule {}

Hi,
I don’t get you point completly:

If you clean your RAM on your Android, then the Storage won’t be cleaned.
your token or the way how you make an authentication should stay in the storage, even if you use the default storage from ionic.

If you make a browser clean, then it is a normal behaviour that your storage is deleted. Then the user should login again. It is everywhere like that.

Csaba

Hi,
Thanks for replying, :slight_smile:

What I want to achieve is that, if the user logged in once and cleaned the ram, the login details are stored in storage, so when opening the app again to go to the homepage using the stored data, and only if he logged out to be sent to the login page since the data in storage is cleaned.

What I’m getting with this code is, that the token is saved in the storage, but when I clean the RAM I’m always getting sent to the login page.

Hi,

as I wrote. I don’t think that Memory Clean will also delete your storage of your browser.

What I would suggest, make a very simple code and test it. If that’s okay, then you have something with your authentication part.

Hope it will help you,Csaba