Closed michaelcuneo closed 5 years ago
@michaelcuneo sorry about that but for now there is some confusing part about the federate user sign in. We are working to provide a uniformed way to retrieve the jwt token. Can you tell me which way you are signing the federated users in? Using Cognito hosted UI
or Auth.federatedSignIn
? Or any component from aws-amplify-react
?
Related to #980
Slightly different to #980 It is indeed the same purpose, but using different methods. I'm using the aws-amplify-react's Authenticator HOC.
@michaelcuneo can you paste some code snippet about how you are using the Authenticator HOC?
The Authenticator HOC is inside it's own component, and it's being shown or not based on loggedIn() ? results in my react-router switch. All of this is irrelevant as to why aws amplify is storing and returning an 'authToken instead of a .JWT' from the cache, but here's my code anyway.
AuthLogin container. https://pastebin.com/Q8vikADi
App Container. https://pastebin.com/UGQ6UcWi
Inside the SAGA that runs all my actions after login. I've tried multiple ways to get the .JWT of a Facebook user. But it seems that Cognito only stores some access token or something instead.
old method of getting the .JWT token.
// Get the current credentials if they exist.
const userInfo = yield call(getCurrentCredentials);
/* .JWT is not returned so try a different method to get a .JWT */
if (userInfo.params.Logins['graph.facebook.com']) {
token = userInfo.params.Logins['graph.facebook.com'];
decoded = decode(token);
user = {
userName: `${decoded.given_name} ${decoded.family_name}`,
picture: decoded.picture,
};
}
new method of getting the .JWT token.
token = GetToken();
.
.
.
async function GetToken() {
return Cache.getItem('federatedInfo');
}
It seems that it doesn't matter what method I used to get a .JWT token for Facebook logins, because it just doesn't store a .JWT.
My old method using the result from userInfo.params.Logins['graph.facebook.com'] also gave me an access token, not a .JWT.
I can get a .JWT from my Cognito User Pool users, and my Google users, which can be used to grab their name, email, photos, etc... but not Facebook. The code doesn't appear to be the problem, it's the cache, or storage, storing something that isn't a .JWT for Facebook logins. I don't know what it is though... I've tried modifying the project end on Facebook, but still no .JWT's for FB.
If I was able to map the username/email/picture etc to cognito user pools on signin, that would be great, I could just grab that info out of there instead... but without the .JWT token there's nothing to grab from anywhere.
First I want to make it clear is that there are two different ways for users to "sign in" with federated users:
external
users and you can use Auth.currentSession()
to get the current session and then get the JWT token like what you do with Cognito users.session
because in this case you have no session
but only a token
from Facebook or Google. Amplify
will store that token into Cache
so you can achieve that.You are using the second the way to log user in and it is correct to get the JWT token by Cache.getItem('federatedInfo')
. Since we didn't do anything with that JWT token from Facebook except putting it into the cache so for now I have no clue about this issue. But I can try to reproduce it and maybe find a way to solve. Thanks.
Just to test this out properly, I've reproduced it in an App that I set up from scratch just now.
Here are my methods to reproduce.
npx create-react-app test-app cd test-app npm install aws-amplify npm install aws-amplify-react npm run start
opened the project and replaced the App.js with the following code. (Important info replaced with xxxxx's for this post)
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Amplify, { Cache, Hub } from 'aws-amplify';
import { Authenticator } from 'aws-amplify-react';
import awsExports from './aws-exports';
Amplify.configure(awsExports);
class App extends Component {
constructor(props) {
super(props);
this.state = {
provider: null,
token: null,
};
Hub.listen('auth', this, 'LoginListener');
}
onHubCapsule(capsule) {
const { channel, payload } = capsule;
if (channel === 'auth') { this.onAuthEvent(payload); }
}
async onAuthEvent(payload) {
const { event, data } = payload;
switch (event) {
case 'signOut':
Cache.clear();
this.setState({
provider: null,
token: null,
})
break;
case 'signIn':
const federatedInfo = await this.getFederatedInfo();
if (federatedInfo) {
this.setState({
provider: federatedInfo.provider,
token: federatedInfo.token,
});
}
break;
default:
}
}
async getFederatedInfo() {
return await Cache.getItem('federatedInfo');
}
render() {
let token = this.state.token;
let provider = this.state.provider;
const federated = {
google_client_id: 'xxxxxxxx.apps.googleusercontent.com',
facebook_app_id: 'xxxxxxxx',
};
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<Authenticator federated={federated} />
{ provider? <p>{provider}</p> : <p> NO PROVIDER YET</p> }
{ token? <p>{token}</p> : <p>NO TOKEN YET</p> }
</div>
);
}
}
export default App;
The aws-exports.js is set up with typical Facebook / Google / Cognito information from an aws-mobile setup. (Important info replaced with xxxxx's for this post)
const awsmobile = {
'aws_app_analytics': 'enable',
'aws_auth_facebook': 'enable',
'aws_cloud_logic': 'enable',
'aws_cloud_logic_custom': [{"id":"xxxxx","name":"imageSetsCRUD","description":"","endpoint":"https://xxxxx.execute-api.ap-southeast-2.amazonaws.com/Development","region":"ap-southeast-2","paths":["/imageSets","/imageSets/123"]},{"id":"xxxxx","name":"userSettingsCRUD","description":"","endpoint":"https://xxxxx.execute-api.ap-southeast-2.amazonaws.com/Development","region":"ap-southeast-2","paths":["/userSettings","/userSettings/123"]}],
'aws_cognito_identity_pool_id': 'ap-southeast-xxxxx',
'aws_cognito_region': 'ap-southeast-2',
'aws_content_delivery': 'enable',
'aws_content_delivery_bucket': 'koalacall-hosting-mobilehub-xxxxx',
'aws_content_delivery_bucket_region': 'ap-southeast-2',
'aws_content_delivery_cloudfront': 'enable',
'aws_content_delivery_cloudfront_domain': 'xxxxx.cloudfront.net',
'aws_dynamodb': 'enable',
'aws_dynamodb_all_tables_region': 'ap-southeast-2',
'aws_dynamodb_table_schemas': [{"tableName":"xxxxx","attributes":[{"name":"userId","type":"S"},{"name":"currentImageSet","type":"S"},{"name":"exclusionSet","type":"NS"},{"name":"shownSettings","type":"BOOL"}],"indexes":[],"region":"ap-southeast-2","hashKey":"userId"},{"tableName":"koalacall-mobilehub-887331565-imageSets","attributes":[{"name":"imageSetId","type":"S"},{"name":"status","type":"S"},{"name":"imageCount","type":"S"},{"name":"sa2Id","type":"N"}],"indexes":[{"indexName":"status","hashKey":"status"}],"region":"ap-southeast-2","hashKey":"imageSetId","rangeKey":"status"}],
'aws_facebook_app_id': 'xxxxx',
'aws_facebook_app_permissions': 'public_profile',
'aws_google_app_permissions': 'email,profile,openid',
'aws_mandatory_sign_in': 'enable',
'aws_mobile_analytics_app_id': 'xxxxx',
'aws_mobile_analytics_app_region': 'us-east-1',
'aws_project_id': 'xxxxx',
'aws_project_name': 'Koala Call',
'aws_project_region': 'ap-southeast-2',
'aws_resource_bucket_name': 'xxxxx',
'aws_resource_name_prefix': 'xxxxx',
'aws_sign_in_enabled': 'enable',
'aws_user_files': 'enable',
'aws_user_files_s3_bucket': 'xxxxx',
'aws_user_files_s3_bucket_region': 'ap-southeast-2',
'aws_user_pools': 'enable',
'aws_user_pools_id': 'xxxxx',
'aws_user_pools_web_client_id': 'xxxxx',
}
export default awsmobile;
And here are my results after successfully logging in with Cognito / Facebook & Google.
As you can see... the Facebook result is not a valid .JWT.
@michaelcuneo yeah you are right. Facebook returns an access token
rather then a .JWT token
. Seems like you need to fb.api('/me', response)
to get those user attributes.
Is that even possible? fb doesn't exist in my app... I'm using Authenticator. That's the whole point of using this HoC... to have it automatically do all of the stuff that I would normally have done manually.
So if there's no Cache < -- > response or Auth.
@michaelcuneo you can get the facebook object by using window.fb
. The HOC is just a wrapper around the facebook login and Facebook only provides a token which is not .JWT. You are right that we should provide a uniformed way to get user info.
I'm still pretty confused by all this too. @powerful23 when using the second way you mentioned above (Federated Identities and Cache.getItem('federatedInfo')
) how are you meant to use that token
to authenticate requests? The token I get from a non-federated flow via Auth.currentSession().idToken.jwtToken
I can just send in an authorization
header to the back-end and it works fine, but when I try sending the federated token in it's place, I'm not authorised.
Docs here don't really make it clear... unless I'm just being thick! ;-)
@vonkanehoffen the federatedInfo token is the access token from Facebook for example. You can use that to query FB for user info directly.
I am using AppSync and need to send the JWT token in the header. But there isn't any JWT! Does that mean AppSync with Cognito Pools based auth, will not work with FB and Google. And I would have to change it to IAM based auth in AppSync? Thats isn't pretty.
Below is what I am trying to do:
get the access token:
const accessToken = (await Auth.currentSession()).getIdToken().getJwtToken();
Set it in the header:
"x-api-key" : `${process.env.SF_AWS_APPSYNC_API_KEY}`,
authorization : `${accessToken}`
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This issue has been automatically closed because of inactivity. Please open a new issue if are still encountering problems.
This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.
Looking for a help forum? We recommend joining the Amplify Community Discord server *-help
channels or Discussions for those types of questions.
When I log people in, I'm using session.idToken.jwtToken to get a token for the Cognito user information, which works fine...
When I log federated users in, I'm using the result from Cache.getItem, to get a token for the Federated Info...
Google will return me a valid .JWT token full of user information, name, picture, email, etc.
Facebook returns me some kind of Token that isn't a valid .JWT
This works to authenticate me against all the things that I need to be accessing after I've logged in... but it has no information that I can extract using normal jwtDecode methods. I've been trying to get this to work for days. There really shouldn't need to be three different ways to get the information of a user.