4
votes

I am having a hard time using Firebase as an Open ID Connect provider. Can you please further describe the steps you have been through before and after to make this work?

For information, here is what I have done so far: In AWS Console:

1 - Create an IAM Identity Provider ( OpenID Connect ) and used securetoken.google.com/<FIREBASE_PROJECT_ID> as an URL, <FIREBASE_PROJECT_ID>for Audience

2 - Checked the Thumbprint manually (it matches the one generated by AWS)

3 - Created a role with the permissions to access the desired services

4 - Created an Identity Pool in Cognito and selected my newly created role in the 'Authenticated role' Dropdown

5 - Selected my Identity Provider under the Authentication Providers > OpenID category (format is therefore): securetoken.google.com/<FIREBASE_PROJECT_ID>

In my code (I am using Vue.js) here are the logical steps I went through:

  • Import / setup AWS SDK

  • Invoke Firebase Auth service

  • Create a new CognitoIdentity
  • Use the getOpenIdTokenForDeveloperIdentity and push the tokenID received from Firebase

The issue is that I keep getting "Missing credentials in config" errors.

The code:

import axios from 'axios';
const AWS = require('aws-sdk');

AWS.config.region = 'eu-west-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
  IdentityPoolId: 'MY_COGNITO_POOL_ID',
});

export default {
  name: 'My Vue.js component name',
  data() {
    return {
      email: '',
      password: '',
      msg: '',
    };
  },
  methods: {
    submit() {
      axios
        .post(
          'https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=MY_KEY',
        {
          email: this.email,
          password: password,
          returnSecureToken: true,
        },
        )
        .then((res) => {
         // stores tokens locally
          localStorage.setItem('jwt', JSON.stringify(res.data));
          const cognitoidentity = new AWS.CognitoIdentity();
          const params = {
            IdentityPoolId: 'MY_COGNITO_POOL_ID',
            Logins: {
              'securetoken.google.com/<PROJECT_ID>': res.data.idToken,
            },
            IdentityId: null,
            TokenDuration: 3600,
          };
          cognitoidentity.getOpenIdTokenForDeveloperIdentity(params, (err, data) => {
            if (err) console.log(err, err.stack); // an error occurred
            else console.log(data);           // successful response
          });
        });
    },
  },
};

Here are the resources I have used so far while attempting to make this work:

http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc_verify-thumbprint.html

Using Firebase OpenID Connect provider as AWS IAM Identity Provider

https://github.com/aws/amazon-cognito-identity-js/blob/master/examples/babel-webpack/src/main.jsx

http://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetCredentialsForIdentity.html

https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication/

https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication-part-2-developer-authenticated-identities/

https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication-part-3-roles-and-policies/

https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication-part-4-enhanced-flow/

2
Did you have to do any configuration on the Firebase project side to get this to work? Seems like, given the firebase project id, a user's email and password, they could use this method without even the Firebase project owner knowing.Jeremy

2 Answers

2
votes

The final code if that can be any help for anyone:

import axios from 'axios';

const AWS = require('aws-sdk');
const aws4 = require('aws4');

export default {
  name: 'VUE_CPNT_NAME',
  data() {
    return {
      email: '',
      password: '',
      msg: '',
      idToken: '',
    };
  },
  methods: {
    submit() {
      // Firebase SignIn API
      // Doc: https://firebase.google.com/docs/reference/rest/auth/
      axios
        .post(
          'https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=[MY_KEY]',
        {
          email: this.email,
          password: this.password,
          returnSecureToken: true,
        },
        )
        .then((res) => {
          this.idToken = res.data.idToken;
          localStorage.setItem('jwt', JSON.stringify(res.data));
          AWS.config.credentials = new AWS.CognitoIdentityCredentials({
            IdentityPoolId: 'IDENTITY_POOL_ID',
            Logins: {
              'securetoken.google.com/<FIREBASE_PROJECT_ID>': res.data.idToken,
            },
          }, {
            region: 'eu-west-1',
          });
          // AWS.config.crendentials.get() methods works as well
          // or a call to cognitoidentity.getId() followed by a call to getCredentialsForIdentity() 
          // will achieve the same thing. Cool. But why!?
          AWS.config.getCredentials((err) => {
            if (err) {
              console.log(err);
            }
            const request = {
              host: 'API_GATEWAY_ENDPOINT.eu-west-1.amazonaws.com',
              method: 'GET',
              url: 'https://API_GATEWAY_ENDPOINT.eu-west-1.amazonaws.com/PATH',
              path: '/API_ENDPOINT_PATH',
            };
            // Signing the requests to API Gateway when the Authorization is set AWS_IAM.
            // Not required when Cognito User Pools are used
            const signedRequest = aws4.sign(request,
              {
                secretAccessKey: AWS.config.credentials.secretAccessKey,
                accessKeyId: AWS.config.credentials.accessKeyId,
                sessionToken: AWS.config.credentials.sessionToken,
              });
            // removing the Host header to avoid errors in Chrome
            delete signedRequest.headers.Host;
            axios(signedRequest);
          });
        });
    },
  },
};
1
votes
  • Try setting the login map i.e the firebase token in the CognitoIdentityCredentials object. See this doc.

    AWS.config.credentials = new AWS.CognitoIdentityCredentials({
          IdentityPoolId: 'MY_COGNITO_POOL_ID',
          Logins: {
            'securetoken.google.com/': 
          }
    });
  • Try calling get method on the credentials object before initializing the Cognito client. You can also use getCredentials instead.
  • If the above steps do not work & they should, pass the credentials as an option while initializing the Cognito client. See this doc for options available while using the CognitoIdentity constructor.

    const cognitoidentity = new AWS.CognitoIdentity({credentials: AWS.config.credentials});
  • If you still receive the error, try logging credentials object in the console after calling the get() method. Ideally, it should have temporary credentials (accessKey, secretKey & sessionToken)