aws cognito user get id token android - android

I'm trying to get the current logged in user's id token for aws cognito in android.
I found this example:
session.getIdToken().getJWTToken()
where session is a CognitoUserSession object
I can't seem to figure out a way to get the current cognitousersession after the login call has been made.
I'm using the default authenticator activity from the notes tutorial:
https://docs.aws.amazon.com/aws-mobile/latest/developerguide/tutorial-android-aws-mobile-notes-auth.html
It says that the tokens are stored in the shared preferences, but I can't figure out how to retrieve them on future activities so that I can make calls to the api gateway using the id token.

The AWS Android SDK will return the JWT token without a network call when the token is not/will not expire.
The threshold for when a token should be refreshed can be set with the CognitoIdentityProviderClientConfig.setRefreshThreshold(long) method.
If you are stil curious how to retrieve the token yourself, then the code can be found in readCachedTokens() method
https://github.com/aws/aws-sdk-android/blob/master/aws-android-sdk-cognitoidentityprovider/src/main/java/com/amazonaws/mobileconnectors/cognitoidentityprovider/CognitoUser.java#L2116

As nobody has answered yet, this might help you out, be aware this is JS code:
This is my routine to receive the session from an already logged in user.
after this, i'm able to access tokens.
var user_data = {
UserPoolId: AWSConfiguration.UserPoolId,
ClientId: AWSConfiguration.ClientAppId
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(user_data);
if (userPool.getCurrentUser() != null) {
userPool.getCurrentUser().getSession(function (err, session) {
if (err) {
window.location.href = "login.html";
}
var user_params = {
IdentityPoolId: AWSConfiguration.IdPoolId,
Logins: {
'cognito-idp.eu-central-1.amazonaws.com/eu-central-1_XXX':session.idToken.jwtToken
}
};
AWS.config.credentials = new AWS.CognitoIdentityCredentials(user_params);
AWS.config.region = AWSConfiguration.region;
AWS.config.credentials.refresh((error) => {
if (error) {
console.error(error);
}
else {
user_is_authenticated();
}
});
});
}

Related

Flutter: FirebaseAuth token error: The custom token format is incorrect. Please check the documentation

I'm working with Line App Login in Flutter, I can get user token in Line API but I'm stuck what to do next.
Right now I'm trying to use it in FirebaseAuth.instance.signInWithCustomToken(token:customToken), but it doesn't work. The error log says "PlatformException(ERROR_INVALID_CUSTOM_TOKEN, The custom token format is incorrect. Please check the documentation. [ Invalid assertion format. ], null)" are there a work around for this?
lineSignIn() async {
_flutterLineLogin.startLogin(_onLoginSuccess, _onLoginError);
}
void _onLoginSuccess(dynamic value) {
FirebaseAuth.instance.signInWithCustomToken(token:value['accessToken'].toString()).then((onValue) {
if (onValue != null) {
///this should be success
}
}).catchError((onError) {
print(onError.toString());
});
}
void _onLoginError(Object error) {
debugPrint("PlatformException: ${error}");
}
All I need is to authenticate the token in firebase. thanks everyone in advance!
Use FirebaseAuth.instance.signInWithCredential instead of FirebaseAuth.instance.signInWithCustomToken
I were also using the same source and trying to get the AuthResult with Firebase instance but failed with below FirebaseAuth error.
PlatformException(ERROR_INVALID_CUSTOM_TOKEN, The custom token format
is incorrect. Please check the documentation. [ Invalid assertion
format. 3 dot separated segments required. ], null)
for example, See below Facebook login source:
_loginFacebookUser() async {
try {
// getting token using email or public profile
_facebookLogin.logIn(["email", "public_profile"]).then((FacebookLoginResult fbResult) {
if (fbResult != null) {
// if facebook login result is loggedIn then
if (fbResult.status == FacebookLoginStatus.loggedIn) {
String facebookToken = fbResult.accessToken.token;
print("facebookToken is: ${facebookToken}");
AuthCredential credential = FacebookAuthProvider.getCredential(accessToken: facebookToken);
// generating firebase authResult for facebook
// FirebaseAuth.instance.signInWithCustomToken(token: facebookToken).then((AuthResult authResult) {
//
// AdditionalUserInfo userInfo = authResult.additionalUserInfo;
// print("facebook userName is: ${userInfo.username}");
// print("facebook user profile is: ${userInfo.profile}");
//
// }).catchError((error) {
// print("error occurred while firebase tokenizing: $error");
// });
FirebaseAuth.instance.signInWithCredential(credential).then((AuthResult authResult) {
AdditionalUserInfo userInfo = authResult.additionalUserInfo;
print("facebook userName is: ${userInfo.username}");
print("facebook user profile is: ${userInfo.profile}");
}).catchError((error) {
print("error occurred while firebase tokenizing: $error");
});
}
} else {
print("facebook login result is null");
}
}).catchError((error) {
print("facebook login error: $error");
});
setState(() {});
} catch (error) {
print("error occurred while loggin: $error");
}
}
hope it will help someone.
Same, for me...
As far as I'm concerned, I use a Webview to talk with my Firebase API (which is globally an Instagram API call with the creation of a Firebase JWT) and when I enter the token that I passed in a cookie to the function FirebaseAuth.instance.signInWithCustomToken()... I got the same error PlatformException(ERROR_INVALID_CUSTOM_TOKEN, The custom token format is incorrect. Please check the documentation.
I passed my JWT to jwt.io and it seems correct... But not for Firebase : Decoded JavaScript Web Token IMAGE.
Is this error related to Firebase or Flutter ?
If someone know where is the error...
please let me know.
Have a good day.

AWS API Gateway Custom Authorizer based on User Groups

I'm attempting to design a system where users are created in my AWS user pool and assigned to one of four user groups. These user groups have roles attached to them which specify the API Calls they are allowed to make. I've created a user for each group and I'm able to successfully log into them in my Android Application. My User Pool is also attached to an Identity Pool for handling Single Sign On with Identity Federation.
The problem is that rather than assuming the Role assigned to the user group, when I log into the user, the role assigned to the user seems to be coming from the Identity Pool rather than their User Group, and as a result they're unable to make the api calls that they should have access to.
I'm attempting to fix this by implementing a Custom Authorizer in Node.js, but the script appears to be running into some problems. Whenever it enters the ValidateToken() method, it fails saying that the token isn't a JWT token.
console.log('Loading function');
var jwt = require('jsonwebtoken');
var request = require('request');
var jwkToPem = require('jwk-to-pem');
var groupName = 'MY_GROUP_NAME';
var roleName = 'MY_ROLE_NAME';
var policyName = 'MY_POLICY_NAME';
var userPoolId = 'MY_USER_POOL_ID';
var region = 'MY_REGION';
var iss = 'https://cognito-idp.' + region + '.amazonaws.com/' + userPoolId;
var pems;
exports.handler = function(event, context) {
//Download PEM for your UserPool if not already downloaded
if (!pems) {
//Download the JWKs and save it as PEM
request({
url: iss + '/.well-known/jwks.json',
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
pems = {};
var keys = body['keys'];
for(var i = 0; i < keys.length; i++) {
//Convert each key to PEM
var key_id = keys[i].kid;
var modulus = keys[i].n;
var exponent = keys[i].e;
var key_type = keys[i].kty;
var jwk = { kty: key_type, n: modulus, e: exponent};
var pem = jwkToPem(jwk);
pems[key_id] = pem;
}
//Now continue with validating the token
ValidateToken(pems, event, context);
} else {
//Unable to download JWKs, fail the call
context.fail("error");
}
});
} else {
//PEMs are already downloaded, continue with validating the token
ValidateToken(pems, event, context);
};
};
function ValidateToken(pems, event, context) {
var token = event.authorizationToken;
//Fail if the token is not jwt
var decodedJwt = jwt.decode(token, {complete: true});
if (!decodedJwt) {
//THIS IS WHERE THE SCRIPT ENDS UP
console.log("Not a valid JWT token");
context.fail("Unauthorized - Invalid Token Provided");
return;
}
//Fail if token is not from your UserPool
if (decodedJwt.payload.iss != iss) {
console.log("invalid issuer");
context.fail("Unauthorized - Invalid Issuer Provided");
return;
}
//Reject the jwt if it's not an 'Access Token'
if (decodedJwt.payload.token_use != 'access') {
console.log("Not an access token");
context.fail("Unauthorized - Not an Access Token");
return;
}
//Get the kid from the token and retrieve corresponding PEM
var kid = decodedJwt.header.kid;
var pem = pems[kid];
if (!pem) {
console.log('Invalid access token');
context.fail("Unauthorized - Invalid Access Token Provided");
return;
}
//Verify the signature of the JWT token to ensure it's really coming from your User Pool
jwt.verify(token, pem, { issuer: iss }, function(err, payload) {
if(err) {
console.log(err, err.stack); // an error occurred
context.fail("Unauthorized - Could not verify token signature");
}
else {
//Valid token. Generate the API Gateway policy for the user
//Always generate the policy on value of 'sub' claim and not for 'username' because username is reassignable
//sub is UUID for a user which is never reassigned to another user.
var principalId = payload.sub;
var username = payload.username;
var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
var params = {
UserPoolId: userPoolId, /* ID of the Target User Pool */
Username: username, /* Provided by event object??? */
Limit: 0,
NextToken: '' //May need actual token value
};
cognitoidentityserviceprovider.adminListGroupsForUser(params, function(err, data) {
if (err){
console.log(err, err.stack); // an error occurred
context.fail("Unauthorized - Could not obtain Groups for User");
}
else{
var groups = data.Groups;
var numGroups = groups.length;
var isFound = false;
for(var i = 0; i < numGroups; i++){
if(groups[i].GroupName == groupName){
isFound = true;
}
}
if(isFound){
var iam = new AWS.IAM();
var iamParams = {
PolicyName: policyName, /* Name of the Policy in the User Group Role */
RoleName: roleName /* Name of the User Group Role */
};
iam.getRolePolicy(params, function(err, data) {
if (err){
console.log(err, err.stack); // an error occurred
context.fail("Unauthorized - Could not acquire Policy for User Group Role");
}
else {
var policy = data.PolicyDocument;
context.succeed(policy); //May need to build policy
}
});
}
else{
context.fail("Unauthorized - Could not find the required User Group under the User");
}
}
});
}
});
}
Can anybody identify the problem with this script, or perhaps help me identify why the tokens being set aren't valid JWT tokens? The tokens are sent by an Android Application using the AWS Cognito SDK.
EDIT: Upon further investigation, the token retrieved from event.authorizationToken is of the following format (the [VALUE] blocks are to hide potentially sensitive information):
AWS4-HMAC-SHA256 Credential=[VALUE1]/20170329/us-east-1/execute-api/aws4_request,
SignedHeaders=host;x-amz-date;x-amz-security-token,
Signature=[VALUE2]
If clients are getting the AWS credentials after login, you can only use AWS_IAM authorization type on the API Gateway Methods. The authorizationToken value you are seeing is the AWS signature generated by the client using the credentials vended by Cognito. It will not be possible for you to validate the AWS signature in a custom authorizer.
Are you following this Cognito blog post? If so, I think you might be confusing the User Group role with the authenticated role selection on the Identity Pool. When you use the federated identities with User Pool provider, your client will get back AWS credentials that have the permissions of the 'Authenticated role' from that section in the Cognito tab in the Identity Pool. In the blog post this would be the 'EngineerRole' set on the Identity Pool.
I figured it out:
This document (specifically the bottom part) says "If you set roles for groups in an Amazon Cognito user pool, those roles are passed through the user's ID token. To use these roles, you must also set Choose role from token for the authenticated role selection for the identity pool."
All it takes is to set the appropriate Trust Policy on each role, adjust the Identity Pool to use "Choose role from token" with the user pool authentication provider, and the proper roles are now being assumed. For others running into this problem, here is my trust policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "[IDENTITY_POOL_ID]"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
}
}
]
}

The Facebook login doesn't work anymore since I upgraded the Firebase app to the new Console (only)

I had a working app with Facebook & Email Login feature, since I upgrade the Firebase console (only, the sdk has not been update).
The app release before the Firebase 3.0 was working before, but it is not anymore able to sign/log with Facebook after the console has been upgraded.
What I have done:
1 - Upgraded the Firebase console
Because of Firebase & Facebook console update, I also had to put the Oauth Callback to the Facebook App
2 - Pasted the Firebase Facebook OAuth Callback to the Facebook console (before it was void) `https://xxx.firebaseapp.com/__/auth/handler``
The Exception:
The firebase Auth listener trigger a Firebase Error :
Invalid authentication credentials provided. and Facebook :
{"providerErrorInfo":{"code":400,"message":"Unsuccessful debug_token
response from Facebook: {\"error\":{\"message\":\"(#100) You must
provide an app access token or a user access token that is an owner or
developer of the
app\",\"type\":\"OAuthException\",\"code\":100,\"fbtrace_id\":\"DG4lLRJHFBS\"}}"}}
The FirebaseError Code:
In the decompiled code of the FirebaseAndroidSdk, the error object is:
0 = {java.util.LinkedHashMap$LinkedEntry#22680} "code" ->
"INVALID_CREDENTIALS"
1 = {java.util.LinkedHashMap$LinkedEntry#22681}
"message" -> "Invalid authentication credentials provided."
2 = {java.util.LinkedHashMap$LinkedEntry#22682} "details" ->
"{"providerErrorInfo":{"code":400,"message":"Unsuccessful debug_token
response from Facebook: {\"error\":{\"message\":\"(#100) You must
provide an app access token or a user access token that is an owner or
developer of the app\",\"type\":\"OAuthException\",\"code\":100,\"fbtrace_id\":\"BtB3JF2qmku\"}}"}}"
with the decompiled code:
private void makeAuthenticationRequest(String urlPath, Map<String, String> params, AuthResultHandler handler) {
final AuthenticationManager.AuthAttempt attempt = this.newAuthAttempt(handler);
this.makeRequest(urlPath, HttpRequestType.GET, params, Collections.emptyMap(), new RequestHandler() {
public void onResult(Map<String, Object> result) {
Object errorResponse = result.get("error");
String token = (String)Utilities.getOrNull(result, "token", String.class);
if(errorResponse == null && token != null) {
if(!AuthenticationManager.this.attemptHasBeenPreempted(attempt)) {
AuthenticationManager.this.authWithCredential(token, result, attempt);
}
} else {
FirebaseError error = AuthenticationManager.this.decodeErrorResponse(errorResponse);
AuthenticationManager.this.fireAuthErrorIfNotPreempted(error, attempt);
}
}
public void onError(IOException e) {
FirebaseError error = new FirebaseError(-24, "There was an exception while connecting to the authentication server: " + e.getLocalizedMessage());
AuthenticationManager.this.fireAuthErrorIfNotPreempted(error, attempt);
}
});
}
At AuthListener level, the firebaseError code : -20
https://www.firebase.com/docs/java-api/javadoc/com/firebase/client/FirebaseError.html
The specified authentication credentials are invalid.
The Facebook Error Code:
code 400
Nothing relevant found here : https://developers.facebook.com/docs/graph-api/using-graph-api/#errors
The code for Authing:
public void authWithFirebase(final String provider, Map<String, String> options) {
if (options.containsKey(AUTH_OPTIONS_ERROR)) {
EventBus.getDefault().post(new MessageToDisplayEvent(options.get(AUTH_OPTIONS_ERROR), true));
} else {
if (provider.equalsIgnoreCase(AUTH_PROVIDER_TWITTER)) {
// if the provider is twitter, we must pass in additional options, so use the options endpoint
ref.authWithOAuthToken(provider, options, new AuthResultHandler(provider));
} else {
// if the provider is not twitter, we just need to pass in the oauth_token
ref.authWithOAuthToken(provider, options.get(AUTH_OPTIONS_TOKEN), new AuthResultHandler(provider));
}
}
}
TOKEN Validity:
From the code above, the Token is confirmed valid since :
https://graph.facebook.com/app?access_token=%7Byour_access_token%7D return a valid JSON
And the Facebook Tool AccessToken https://developers.facebook.com/tools/debug/accesstoken return a still valid TOKEN
What changed from user point of view:
Now, When I click on the FacebookLoginButton, I have a new dialog that ask "connection as %FacebookUserName", with 2 buttons ("Unconnect" & "Cancel")
I posted a bug report at Firebase, but I even do not know if this is Facebook or Firebase, any help, advise for exploring new issue surface or solution is welcome.
In Facebook Developper Console, switch-off the option about the "app key that is integrated in the client".
For me this changed the behavior. I will give more information as far I get from Firebase/Facebook
Here is a French Screenshot to help you setting up Facebook:

Google+ Sign In cross client(android/web) authentication

i'm trying to integrate 'Log in with Google' in app that have an android and web component. Everything in the web component is working fine with the following steps:
1. Rendering the view with an anti-forgery token, client id and app name.
$state = md5(rand());
Session::set('state', $state);
$this->view->render('login', array(
'CLIENT_ID' => 'my_web_client_id',
'STATE' => $state,
'APPLICATION_NAME' => 'my_app_name'));
2. When user clicks on the Google's SignIn button, obtain the one-time code from Google's servers and send it to my server.
3. After my server receives the one-time code using https://github.com/google/google-api-php-client to authenticate the user with that code.
if ($_SESSION['state'] != $_POST['state']) { // Where state is the anti-forgery token
return 'some error';
}
$code = $_POST['code'];
$client = new Google_Client();
$client->setApplicationName("my_app_name");
$client->setClientId('my_web_client_id');
$client->setClientSecret('client_secret');
$client->setRedirectUri('postmessage');
$client->addScope("https://www.googleapis.com/auth/urlshortener");
$client->authenticate($code);
$token = json_decode($client->getAccessToken());
// Verify the token
$reqUrl = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=' . $token->access_token;
$req = new Google_Http_Request($reqUrl);
$tokenInfo = json_decode($client->getAuth()->authenticatedRequest($req)->getResponseBody());
// If there was an error in the token info, abort.
if ($tokenInfo->error) {
return 'some error';
}
// Make sure the token we got is for our app.
if ($tokenInfo->audience != "my_web_client_id") {
return 'some error';
}
// Saving user in db
...
// Load the app view
Now, for android client should be something similar, right? Following these tutorials:https://developers.google.com/+/mobile/android/sign-in and http://www.androidhive.info/2014/02/android-login-with-google-plus-account-1/
Executing async task in onConnected method
class CreateToken extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... voids) {
oneTimeCode = getOneTimeCode();
String email = getUserGPlusEmail();
try {
// Opens connection and sends the one-time code and email to the server with 'POST' request
googleLogin(oneTimeCode, email);
} catch (IOException e) {
e.printStackTrace();
}
return oneTimeCode;
}
}
private String getOneTimeCode() {
String scopes = "oauth2:server:client_id:" + SERVER_CLIENT_ID + ":api_scope:" + SCOPE_EMAIL;
String code = null;
try {
code = GoogleAuthUtil.getToken(
LoginActivity.this, // Context context
Plus.AccountApi.getAccountName(mGoogleApiClient), // String accountName
scopes // String scope
);
} catch (IOException transientEx) {
Log.e(Constants.TAG, "IOException");
transientEx.printStackTrace();
// network or server error, the call is expected to succeed if you try again later.
// Don't attempt to call again immediately - the request is likely to
// fail, you'll hit quotas or back-off.
} catch (UserRecoverableAuthException e) {
Log.e(Constants.TAG, "UserRecoverableAuthException");
e.printStackTrace();
// Requesting an authorization code will always throw
// UserRecoverableAuthException on the first call to GoogleAuthUtil.getToken
// because the user must consent to offline access to their data. After
// consent is granted control is returned to your activity in onActivityResult
// and the second call to GoogleAuthUtil.getToken will succeed.
startActivityForResult(e.getIntent(), AUTH_CODE_REQUEST_CODE);
} catch (GoogleAuthException authEx) {
// Failure. The call is not expected to ever succeed so it should not be
// retried.
Log.e(Constants.TAG, "GoogleAuthException");
authEx.printStackTrace();
} catch (Exception e) {
throw new RuntimeException(e);
}
Log.e(Constants.TAG, "ONE TIME CODE: " + code);
return code;
}
After obtaining the code successfully, send it to my server for authentication.
And here's the code on the server:
$code = $_POST['code'];
$client = new Google_Client();
$client->setApplicationName("my_app_name");
$client->setClientId('my_web_client_id'); // Web component's client id
$client->setClientSecret('client_secret'); // Web component's secret
$client->addScope("email");
$client->setAccessType("offline");
$client->authenticate($code);
...
And the problem is that authentication works only once every 10-15 minutes. When trying to obtain the one-time code more than once in 10-15 minutes, i get the same code as the last one(Clearly there is something wrong. This happens only with the android client and i'm getting this error: Error fetching OAuth2 access token, message: 'invalid_grant: i'). Couldn't find anyone with the same problem here in SO. Probably i'm doing something wrong, but can't figure out what is it...Any help would be appreciated.
You shouldn't be sending the code each time. On the web this is kind of OK as when you first consent you'll get a code that gives you offline access (you'll see a refresh token in the response when you exchange it) but in future cases you wont. On Android, you get a code that gives you a refresh token every time, which means you'll need to show the consent every time, and you're likely to run into per-user limits or cache issues (as you seem to be).
The magic extra component you need is a thing called an ID token. This you can get easily on both platforms and tells you who the person is. Take a look at this blog post for more: http://www.riskcompletefailure.com/2013/11/client-server-authentication-with-id.html
The limitation with an ID token is that you can't use it to call Google APIs. All it does is give you the Google user ID, the client ID of the app being used and (if email scope is used) the email address. The nice thing is that you can get one really easily on all platforms with less user interaction, and they're cryptographically signed so most of the time you can use them without making any further network calls on the server. If you don't need to make Google API calls (because you're just using it for auth) this is the best thing to use by far - given that you're just getting the email, I would be inclined to stop here.
If you need to make Google API calls from your server though, then you should use the code - but just once. When you exchange it, you store the refresh token in a database keyed against the user ID. Then, when the user comes back you look up the refresh token and use it to generate a new access token. So the flow would be:
First time:
Android -> Server: id token
Server -> I have no refresh token!
Android -> Server: code
Other times:
Android -> Server: id token
Server - I have a code, and can make calls.
For the web, you can use the same flow or carry on sending the code each time, but you should still keep the refresh token in the database if the response contains one.

Authenticated access to WebAPI via Facebook token from Android App

I'm trying to make my Android Application to log into my WebAPI services. I want to share my ideas in order to verify them.
If the access to WebAPI is performed via WebSite the steps are:
1- Call WebAPI method for logging in
2- WebAPI redirect client to facebook
3- Facebook login and returns a Token
4- If I use that token in the next calls I'll be authenticated as the right user.
And this works.
If the access to WebAPI is performed via Android APP, how can I get the access token?
Actually I'm doing something like:
1- Contact Facebook via Login Button
2- Getting logged id to Facebook receiving a Token
3- Trying to perform WebAPI calls adding the Authentication: Bearer CODE to my calls
At that point I'm wandering..
How can my application now that I'm THAT particular user? If I perform something like
GET /API/METHOD1
Authentication: Bearer CODE
How can it knows that the CODE is me if the Android Application never told him? Does the application automatically contact Facebook in order to receive an answer like "yeah! I release that token, it is related to..."
Or I'm misunderstanding everything?
The other way I can figure it out is that I must use an "hybrid approach" like:
1- Call WebAPI (as via browser)
2- Get Redirect link to Facebook
3- Get the token
But.. At that point, how can I swith between Facebook App / Facebook Site to my Android application again?
Sorry for the mess, I'm trying to find out the logic beside this auth process.
Ok, I think I've got it!
when WebAPI receives the Facebook Token doesn't know anything about user and authorizations. BUT, due to the token, can access to Facebook "as the caller".
By this way the application could perform something like:
Android -> Facebook Login -> Get FBToken
Android -> Web API -> Send FBToken
Web API -> Facebook -> /me Sending FBToken
Facebook -> Web API -> Identity
Web API -> Andoid -> This is the token for you Identity
Android -> Web API -> Give me Auth Method, Authorization: Bearer WebAPIToken
I found out a useful class online: (based on WebApi ASP.NET Identity Facebook login)
private async Task<FacebookUserViewModel> VerifyFacebookAccessToken(string accessToken)
{
FacebookUserViewModel fbUser = null;
var path = "https://graph.facebook.com/me?access_token=" + accessToken;
var client = new HttpClient();
var uri = new Uri(path);
var response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
fbUser = Newtonsoft.Json.JsonConvert.DeserializeObject<FacebookUserViewModel> (content);
}
return fbUser;
}
public class FacebookUserViewModel
{
[JsonProperty("id")]
public string ID { get; set; }
[JsonProperty("first_name")]
public string FirstName { get; set; }
[JsonProperty("last_name")]
public string LastName { get; set; }
[JsonProperty("username")]
public string Username { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
}
So, you could have a WebAPI like:
[HttpGet]
[AllowAnonymous]
public async Task<string> GetTokenFromFacebook(string accessToken)
{
var user = await VerifyFacebookAccessToken(accessToken);
//Search on your DB for the user ID or email
//Get token for user
return token;
}
A complete and perfect explanation is here:
http://thewayofcode.wordpress.com/2014/03/01/asp-net-webapi-identity-system-how-to-login-with-facebook-access-token/
Example of token creation
var tokenExpirationTimeSpan = TimeSpan.FromDays(14);
var identity = new ClaimsIdentity(Startup.OAuthBearerOptions.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, UserName, null, "Facebook"));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.ToString(), null, "LOCAL_AUTHORITY"));
AuthenticationTicket ticket = new AuthenticationTicket(identity, new AuthenticationProperties());
var currentUtc = new Microsoft.Owin.Infrastructure.SystemClock().UtcNow;
ticket.Properties.IssuedUtc = currentUtc;
ticket.Properties.ExpiresUtc = currentUtc.Add(tokenExpirationTimeSpan);
var accesstoken = Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
I hope it helps!

Categories

Resources