Search code examples
angularamazon-web-servicesamazon-cognitoaws-amplifyaws-amplify-cli

Federation requires either a User Pool or Identity Pool in config error - Amplify + Angular


I'm having trouble finding information on how to associate my existing user pool with amplify using Angular. Currently when I click on my Login with Google button, I get this error:

enter image description here

The amplify configure CMD doesn't give an option about a .config file. So I'm not sure how to establish this relationship to make that error go away. I already did amplify init and it went through successfully.

How do I make the connection to the User Pool?

I appreciate any help!

The error happens when I click on the Google login button in login component:

login.component.ts

async signInWithGoogle(): Promise < void > {
    const socialResult =
        await this.authService.socialSignIn(AuthService.GOOGLE);
    console.log('google Result:', socialResult);
}

auth.service.ts

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';
import { Amplify } from 'aws-amplify';
import { Observable } from 'rxjs';
import { BehaviorSubject } from 'rxjs';
import {
  CognitoUserPool,
  CognitoUserAttribute,
  CognitoUser,
  AuthenticationDetails,
  CognitoUserSession
} from 'amazon-cognito-identity-js';
import Auth, { CognitoHostedUIIdentityProvider } from '@aws-amplify/auth'
import { Hub, ICredentials } from '@aws-amplify/core'
import { User } from './user.model';
import awsconfig from '../aws-exports';
Amplify.configure(awsconfig);
const POOL_DATA = {
  UserPoolId: 'us-east-1_fSgUd7X4m',
  ClientId: '<my id was here>'
};

const userPool = new CognitoUserPool(POOL_DATA);

@Injectable({ providedIn: "root" })
export class AuthService {
  authIsLoading = new BehaviorSubject<boolean>(false);
  authDidFail = new BehaviorSubject<boolean>(false);
  authStatusChanged = new Subject<boolean>();
  public loggedIn: boolean;

  private _authState: Subject<CognitoUser | any> = new Subject<CognitoUser | any>();
  authState: Observable<CognitoUser | any> = this._authState.asObservable();

  public static SIGN_IN = 'signIn';
  public static SIGN_OUT = 'signOut';
  public static GOOGLE = CognitoHostedUIIdentityProvider.Google;
  registeredUser: CognitoUser;
  constructor(private router: Router) {
  }

  signUp(username: string, email: string, password: string): void {

    this.authIsLoading.next(true);
    const user: User = {
      username: username,
      email: email,
      password: password
    };
    const attrList: CognitoUserAttribute[] = [];
    const emailAttribute = {
      Name: 'email',
      Value: user.email
    };
    attrList.push(new CognitoUserAttribute(emailAttribute));
    userPool.signUp(user.username, user.password, attrList, null, (err, result) => {
      if (err) {
        console.log(err)
        this.authDidFail.next(true);
        this.authIsLoading.next(false);
        return;
      }
      this.authDidFail.next(false);
      this.authIsLoading.next(false);
      this.registeredUser = result.user;
    });
    return;
  }

  confirmUser(username: string, code: string) {
    this.authIsLoading.next(true);
    const userData = {
      Username: username,
      Pool: userPool
    };
    const cognitUser = new CognitoUser(userData);
    cognitUser.confirmRegistration(code, true, (err, result) => {
      if (err) {
        this.authDidFail.next(true);
        this.authIsLoading.next(false);
        return;
      }
      this.authDidFail.next(false);
      this.authIsLoading.next(false);
      this.router.navigate(['/']);
    });
  }
  socialSignIn(provider: CognitoHostedUIIdentityProvider): Promise<ICredentials> {

    return Auth.federatedSignIn({ provider: provider });
  }
  signIn(username: string, password: string): void {
    this.authIsLoading.next(true);
    const authData = {
      Username: username,
      Password: password
    };
    const authDetails = new AuthenticationDetails(authData);
    const userData = {
      Username: username,
      Pool: userPool
    };
    const cognitoUser = new CognitoUser(userData);
    const that = this;
    cognitoUser.authenticateUser(authDetails, {
      onSuccess(result: CognitoUserSession): void {
        that.authStatusChanged.next(true);
        that.authDidFail.next(false);
        that.authIsLoading.next(false);
        console.log(result);
      },
      onFailure(err): void {
        that.authDidFail.next(true);
        that.authIsLoading.next(false);
        console.log(err);
      }
    });
    this.authStatusChanged.next(true); // create user with cognito data

    return;
  }

  getAuthenticatedUser() {
    return userPool.getCurrentUser();
  }

  logout() {
    this.getAuthenticatedUser().signOut();
    this.authStatusChanged.next(false);
  }

  isAuthenticated(): Observable<boolean> {
    const user = this.getAuthenticatedUser();
    const obs = Observable.create((observer) => {
      if (!user) {
        observer.next(false);
      } else {
        user.getSession((err, session) => {
          if (err) {
            observer.next(false);
          } else {
            if (session.isValid()) {
              observer.next(true);
            } else {
              observer.next(false);
            }
          }
        });
      }
      observer.complete();
    });
    return obs;
  }

  initAuth() {
    this.isAuthenticated().subscribe(
      (auth) => this.authStatusChanged.next(auth)
    );
  }
}

Solution

  • The AWS Amplify auth documentation indicates the following regarding re-use of existing AWS Cognito resources:

    If you want to re-use an existing authentication resource from AWS (e.g. Amazon Cognito UserPool or Identity Pool), update Amplify.configure() method with the following information.

    import Amplify, { Auth } from 'aws-amplify';
    
    Amplify.configure({
        Auth: {
    
            // REQUIRED only for Federated Authentication - Amazon Cognito Identity Pool ID
            identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab',
    
            // REQUIRED - Amazon Cognito Region
            region: 'XX-XXXX-X',
    
            // OPTIONAL - Amazon Cognito Federated Identity Pool Region 
            // Required only if it's different from Amazon Cognito Region
            identityPoolRegion: 'XX-XXXX-X',
    
            // OPTIONAL - Amazon Cognito User Pool ID
            userPoolId: 'XX-XXXX-X_abcd1234',
    
            // OPTIONAL - Amazon Cognito Web Client ID (26-char alphanumeric string)
            userPoolWebClientId: 'a1b2c3d4e5f6g7h8i9j0k1l2m3',
    
            // OPTIONAL - Enforce user authentication prior to accessing AWS resources or not
            mandatorySignIn: false,
    
            // OPTIONAL - Configuration for cookie storage
            // Note: if the secure flag is set to true, then the cookie transmission requires a secure protocol
            cookieStorage: {
            // REQUIRED - Cookie domain (only required if cookieStorage is provided)
                domain: '.yourdomain.com',
            // OPTIONAL - Cookie path
                path: '/',
            // OPTIONAL - Cookie expiration in days
                expires: 365,
            // OPTIONAL - See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
                sameSite: "strict" | "lax",
            // OPTIONAL - Cookie secure flag
            // Either true or false, indicating if the cookie transmission requires a secure protocol (https).
                secure: true
            },
    
            // OPTIONAL - customized storage object
            storage: MyStorage,
    
            // OPTIONAL - Manually set the authentication flow type. Default is 'USER_SRP_AUTH'
            authenticationFlowType: 'USER_PASSWORD_AUTH',
    
            // OPTIONAL - Manually set key value pairs that can be passed to Cognito Lambda Triggers
            clientMetadata: { myCustomKey: 'myCustomValue' },
    
             // OPTIONAL - Hosted UI configuration
            oauth: {
                domain: 'your_cognito_domain',
                scope: ['phone', 'email', 'profile', 'openid', 'aws.cognito.signin.user.admin'],
                redirectSignIn: 'http://localhost:3000/',
                redirectSignOut: 'http://localhost:3000/',
                responseType: 'code' // or 'token', note that REFRESH token will only be generated when the responseType is code
            }
        }
    });
    
    // You can get the current config object
    const currentConfig = Auth.configure();
    

    Please, verify that the awsconfig variable include a similar information or modify it as necessary.