Setup
I'm developing an ionic app that use AWS Amplify as backend. We want to use the following services using both auth types "AMAZON_COGNITO_USER_POOLS" and "API_KEY":
- Amplify API for to interact with API Gateway
- GraphQL API with codegen
For authentication we are using Ionic Auth Connect with Cognito hosted UI. Following the docs we were able to have login and registration working with ability to retrieve Id, Refresh and Access token.
Problem
The problem with this setup is that amplify is not able to recognize logged in users and we are getting no current user error when trying to interact with Amplify API and GraphQL.
Checking both amplify and auth connect docs I found no clear way to set current user manually.
I tried setting the tokens manually using Amplify.configure and using an auth interceptor but it did not work because Amplify has some validation logic within the SDK which blocks the request.
Is there a way to set user session for amplify without having to manually construct API and GraphQL calls ?
CodePudding user response:
Assuming you are using below setup for your auth class: From official docs
import { Injectable, NgZone } from '@angular/core';
import { IonicAuth } from '@ionic-enterprise/auth';
import { Platform } from '@ionic/angular';
import { BehaviorSubject, Observable } from 'rxjs';
import { nativeIonicAuthOptions, webIonicAuthOptions } from '../../environments/environment';
@Injectable({
providedIn: 'root'
})
export class AuthenticationService extends IonicAuth {
private authenticationChange: BehaviorSubject<boolean> = new BehaviorSubject(false);
public authenticationChange$: Observable<boolean>;
constructor(platform: Platform, private ngZone: NgZone) {
super(platform.is('hybrid') ? nativeIonicAuthOptions : webIonicAuthOptions);
this.authenticationChange$ = this.authenticationChange.asObservable();
this.isAuthenticated().then((authenticated) => { this.onAuthChange(authenticated); });
}
public async onLoginSuccess(): Promise<void> {
this.onAuthChange(true);
}
public async onLogout(): Promise<void> {
this.onAuthChange(false);
}
private async onAuthChange(isAuthenticated: boolean): Promise<void> {
this.ngZone.run(() => {
this.authenticationChange.next(isAuthenticated);
});
}
}
You can make use of amazon-cognito-identity-js
and manually set CognitoUserSession
like below:
Install amazon-cognito-identity-js
Create a new method that will handle setting user session:
private async setAmplifyUser(): Promise<void> {
const idToken = await this.getIdToken();
const accessToken = await this.getAccessToken();
const authResponse = await this.getAuthResponse();
const refreshToken = await this.getRefreshToken();
const userPool = new CognitoUserPool({
UserPoolId: `YOUR_USER_POOL_ID `,
ClientId: `YOUR_APP_CLIENT_ID `,
});
const cognitoIdToken = new CognitoIdToken({
IdToken: authResponse.id_token,
});
const cognitoAccessToken = new CognitoAccessToken({
AccessToken: accessToken,
});
const cognitoRefreshToken = new CognitoRefreshToken({
RefreshToken: refreshToken,
});
const username = idToken['cognito:username'];
const user = new CognitoUser({
Username: username,
Pool: userPool,
});
user.setSignInUserSession(
new CognitoUserSession({
AccessToken: cognitoAccessToken,
IdToken: cognitoIdToken,
RefreshToken: cognitoRefreshToken,
})
);
}
To keep Cognito session in sync with auth connect's session you need to call setAmplifyUser
inside onAuthChange
To confirm that your session is set you can try calling these methods:
Auth.currentAuthenticatedUser().then((res) => {
console.log('currentAuthenticatedUser', res);
});
Auth.currentSession().then((res) => {
console.log('currentSession', res);
});
Additional Note on using multiple auth modes:
inside AppModule's constructor you can subscribe to onAuthChange
and switch aws_appsync_authenticationType based on auth state.