How to pass OAuth credential to the reauthenticate method of Firebase auth? - javascript

I found some information on how to create the credentials object that is mentioned in the firebase docs but don't understand how to create the object if the user is authenticated with OAuth and not email and password. Does anyone know how this would work?
var user = firebase.auth().currentUser;
var credentials = firebase.auth.EmailAuthProvider.credential(
user.email,
'yourpassword'
);
user.reauthenticateWithCredential(credentials);

Related

Javascript: Phone firebase auth: How to put email?

I'm trying to allow user that logged with phone firebase auth to put his email.
Note: I don't mean I want to login by email. I mean only put the email to the user auth information if possible.
To set a user's email address you can do:
var user = firebase.auth().currentUser;
user.updateEmail("user#example.com").then(function() {
// Update successful.
}).catch(function(error) {
// An error happened.
});

Getting email from user in Firebase Microsoft Account Authentication

I am using the following code to authenticate a Firebase user who signs in with a Microsoft account:
signInMicrosoft = () => {
var provider = new firebase.auth.OAuthProvider('microsoft.com');
provider.addScope('openid');
provider.addScope('email');
firebase
.auth()
.signInWithPopup(provider)
.then(
function(result) {
console.log('result', result)
var token = result.credential.accessToken;
var user = result.user;
var isNewUser = result.additionalUserInfo.isNewUser;
//window.location.href = "/";
}.bind(this)
)
.catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
this.setState({
loginError: true
});
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
// ...
});
}
However, when I try to access the user's email with the following code:
firebase.auth().onAuthStateChanged(user => {
console.log('user', user)
});
The 'user.email' entry is set to null. How do I enable Firebase to access the Microsoft account's email in this fashion, so that 'user.email' is set to the user's email?
I tried.
I could get email address.
See:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#requesting-individual-user-consent
At this time, the offline_access ("Maintain access to data you have given it access to") and user.read ("Sign you in and read your profile") permissions are automatically included in the initial consent to an application. These permissions are generally required for proper app functionality - offline_access gives the app access to refresh tokens, critical for native and web apps, while user.read gives access to the sub claim, allowing the client or app to correctly identify the user over time and access rudimentary user information
https://learn.microsoft.com/en-us/graph/permissions-reference#openid-permissions
Important The Microsoft Authentication Library (MSAL) currently specifies offline_access, openid, profile, and email by default in authorization and token requests. This means that, for the default case, if you specify these permissions explicitly, Azure AD may return an error.
provider.addScope(); is not necessary.
Please try comment out or delete provider.addScope();
// provider.addScope('openid');
// provider.addScope('email');
And you should check your Microsoft applications settings.
Microsoft Graph Permissions > Delegated Permissions set User.Read.?
Remarks:
provider.addScope('mail.read'); in the following documentation allows the app to read email in user mailboxes.
Not allows the app to read user email address.
https://firebase.google.com/docs/auth/web/microsoft-oauth#handle_the_sign-in_flow_with_the_firebase_sdk
https://learn.microsoft.com/en-us/graph/permissions-reference#mail-permissions

How to authenticate API calls with Cognito using Facebook?

I want to authenticate users using Cognito, with option to use Facebook. User can sign_in/sign_up using either of those options.
I have created Cognito User Pool and Cognito Federated Identity, and also I have created Facebook App for authentication. Both User Pool and Facebook app are connected to Federated identity.
When I sign_up and later authenticate Cognito User via Cognito User Pool, then Cognito returns accessToken, which I store in localStorage on front and use whenever needed for athentication.
I have /authenticate endpoint (express), that takes in username & password, and returns accessToken if all went well. Whenever I make API call that requires auth, I send accessToken that I have in local storage. It goes, more or less as this:
// POST user/authenticate
const authenticationData = {
Username: username,
Password: password
}
authenticationDetails = new AuthenticationDetails(authenticationData)
const userData = {
Username: username,
Pool: userPool()
}
cognitoUser = new CognitoUser(userData)
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: (res) => resolve(res), // here I get accessToken
onFailure: (err) => {
console.log('[authenticateUser error]', err)
reject(err)
},
//...
However
When I use Facebook, I do not get accessToken I could use in same fashion. I get accessToken from Facebook via FB.login, I pass it to Cognito to authenticate, and then I don't know what to do, because I cannot get any token that could be used to authenticate API calls, that require Cognito Authentication.
Here's what I do:
await window.FB.login((response) => {
props.userFacebookSignIn(response)
})
// ...
call(foo, 'users/facebook_sign_in', { accessToken: payload.facebookAccessToken })
// ...
// users/facebook_sign_in
AWS.config.region = config.AWSRegion
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'foo',
Logins: {
'graph.facebook.com': facebookAccessToken
}
})
AWS.config.credentials.get((err) => {
// Here I get no errors, I presume that I have logged Facebook user in
const accessKeyId = AWS.config.credentials.accessKeyId
const secretAccessKey = AWS.config.credentials.secretAccessKey
const sessionToken = AWS.config.credentials.sessionToken
// here I can do stuff probably,
// but I would like to receive token that would allow me to do stuff,
// rather than context I can do stuff in
})
While I am doing all of this, I have this feeling, that devs at AWS implemented Cognito as frontend solution, rather than something to be used in backend. Correct me if I am wrong.
Nevertheless, I would like to be able authenticate api calls using Cognito and Facebook interchangeably in express middleware.
Is that possible? Thanks.
I have used federated identity for salesforce single sign on but i imagine the steps will the same. After authenticating with facebook you will recieve and id_token from them in response. You have to pass this as a parameter in the getId method:
var params = {
IdentityPoolId: 'STRING_VALUE', /* required */
AccountId: 'STRING_VALUE',
Logins: {
'<IdentityProviderName>': 'STRING_VALUE',
/* 'graph.facebook.com': ... */
}
};
cognitoidentity.getId(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
In the result you will get an identity id which you can save somewhere so that you don't have to make this call everytime while authenticating. Now take this identity id and make the getCredentialsForIdentity call:
response = client.get_credentials_for_identity(
IdentityId='string',
Logins={
'string': 'string'
},
CustomRoleArn='string'
)
This will finally give you the temporary access key, secret key and session key you need.
I decided to use oAuth.
Here's quick & dirty look on how it's done
In AWS Cognito
1) Set up Cognito User Pool. Add App Client save App client id & App client secret as COGNITO_CLIENT_ID and COGNITO_CLIENT_SECRET
2) Go to Federation > Identity providers and add your Facebook app ID and App secret (both you will find in Facebook app panel)
3) Go to App integration > App client settings click "Select all", set up your Callback URL, mine is localhost:5000/facebook also select Authorization code grant and Allowed OAuth Scopes (save scopes to say: COGNITO_SCOPES)
4) Now go to App integration > Domain name and enter your custom domain; let's say example-app-debug so it's: https://example-app-debug.auth.us-east-1.amazoncognito.com
That's all there is to Cognito
no the Facebook part
5) Settings > Basic add example-app-debug.auth.us-east-1.amazoncognito.com to your App domains - Save Changes
6) In Facebook Login > Settings in Valid OAuth Redirect URIs add this URL: https://example-app-debug.auth.us-east-1.amazoncognito.com/oauth2/idpresponse and Save Changes
and the code
In browser, redirect user to this url when Login w. Facebook button is clicked:
window.location.href =
`https://example-app-debug.auth.us-east-1.amazoncognito.com/oauth2/authorize` +
`?identity_provider=Facebook` +
`&redirect_uri=http://localhost:5000/facebook` +
`&response_type=code` +
`&client_id=${COGNITO_CLIENT_ID}` +
`&scope=${COGNITO_SCOPES}`
this call should come back to you with a code, like this: http://localhost:5000/facebook?code=foo-bar-code Send this code to your backend.
In backend, do this:
const axios = require('axios')
const url = `` +
`https://${COGNITO_CLIENT_ID}:${COGNITO_CLIENT_SECRET}` +
`#example-app-debug.auth.us-east-1.amazoncognito.com/oauth2/token` +
`?grant_type=authorization_code` +
`&code=foo-bar-code` + // <- code that came from Facebook
`&redirect_uri=http://localhost:5000/facebook` +
`&client_id=${COGNITO_CLIENT_ID}`
const response = await axios.post(url)
// response should have access_token, refresh_token and id_token in data
You send access_token, refresh_token and id_token back to frontend and save them in local storage and use them to authenticate and Done.

Cognito wont switch unauthenticated user to authenticated user

I'm using a Cognito userpool and Cognito federated identities to pass an IAM role to authenticated and unauthenticated users. When I try to switch a user from unauthenticated to authenticated, the developer console doesn't register that the change has happened; it is showing that I have 100% unauthenticated users.
Right now I instantiate my AWS client as an unauthenticated user and then call a function to update the credentials when they are available so I can switch them to authenticated. E.g.:
AWS.config.region = 'us-west-2';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: identityPoolId,
region: 'us-west-2',
Logins: {}
});
const updateCredentials = () => {
const auth = store.getState().auth; //this gets the authentication credentials from a global store.
AWS.config.credentials.Logins = {
'cognito-idp.us-west-2.amazonaws.com/us-west-2_XXXXXXXXX': auth.idToken
};
AWS.config.credentials.expired = true;
};
As best as I can tell, this is the correct way to do this. See the documentation at the bottom of this page, and here, and here.
However, my console shows that I have no authenticated users, so updateCredentials is not switching users to authenticated. What can be done to fix this?
at the end call AWS.config.credentials.get(()....)

AWS cognito for javascript webapp. How to check if cognito token has expired or not

So I have a basic webapp, and Im trying to create user access control using AWS cognito. I have a custom authorisation provider and upon entering correct username password. I do the following in my login page:
//Successful Login
var creds = AWS.config.credentials;
creds.params.IdentityId = output.identityId;
creds.params.Logins = {'cognito-identity.amazonaws.com': output.token};
//Store token in browser cache
localStorage.setItem('token', output.token);
localStorage.setItem('id', output.identityId);
//Launch dashboard
window.location = "./index.html";
Once I redirect the user to the dashboard, I trigger a onLoad function to check whether the user has correct login credentials and not expired ones. Using this:
//read browser cache
var id = localStorage.getItem('id');
var token = localStorage.getItem('token');
//validate session
AWS.config.region = 'ap-northeast-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: id,
Logins: {'cognito-identity.amazonaws.com': token}
});
//check if session is still active
if(AWS.config.credentials.expired) window.location = "./session-expire.html";
Problem is the expired property is always true. no matter what I do. How do you guys check if the credentials are valid?.
Thanks in advance,
Rajan
In the code samples you provided, you never acquire credentials. You set up the credentials provider, but do not call any services with it, or explicitly try to get the credentials.
Secondly, the credentials are not persisted across page loads.
This will lead to the credentials being expired in your code samples.
This question may help you, just replace facebook with your own developer auth flow. AWS.config.credentials are null between page requests

Categories