Reputation: 3964
I'm currently begining to work with Xamarin.Auth
and I'm facing 2 problems for which I'm stuck since 1 day and half..
I have this piece of code :
public class OAuth
{
private Account account;
private AccountStore store;
// These values do not need changing
public string Scope;
public string AuthorizeUrl;
public string AccessTokenUrl;
public string UserInfoUrl;
string clientId;
string redirectUri;
private Func<JObject, User> OAuthParser;
private Action<User> OnCompleted;
private Action<string> OnError;
public OAuth()
{
account = null;
store = null;
Scope = "";
AuthorizeUrl = "";
AccessTokenUrl = "";
UserInfoUrl = "";
clientId = "";
redirectUri = "";
}
public OAuth Facebook()
{
// These values do not need changing
Scope = "public_profile";
AuthorizeUrl = "https://m.facebook.com/dialog/oauth/";
AccessTokenUrl = "";
UserInfoUrl = "";
switch (Device.RuntimePlatform)
{
case Device.iOS:
clientId = "<insert IOS client ID here>";
redirectUri = "<insert IOS redirect URL here>:/oauth2redirect";
break;
case Device.Android:
clientId = "206316176526191";
redirectUri = "http://www.facebook.com/connect/login_success.html";
break;
}
OAuthParser = ParseFacebookResponse;
return this;
}
public OAuth GooglePlus()
{
// These values do not need changing
Scope = "https://www.googleapis.com/auth/userinfo.email";
AuthorizeUrl = "https://accounts.google.com/o/oauth2/auth";
AccessTokenUrl = "https://www.googleapis.com/oauth2/v4/token";
UserInfoUrl = "https://www.googleapis.com/oauth2/v2/userinfo";
switch (Device.RuntimePlatform)
{
case Device.iOS:
clientId = "<insert IOS client ID here>";
redirectUri = "<insert IOS redirect URL here>:/oauth2redirect";
break;
case Device.Android:
clientId = "548539660999-muighch5brcrbae8r53js0ggdad5jt45.apps.googleusercontent.com";
redirectUri = "com.googleusercontent.apps.548539660999-muighch5brcrbae8r53js0ggdad5jt45:/oauth2redirect";
break;
}
OAuthParser = ParseGooglePlusResponse;
return this;
}
public OAuth2Authenticator Authenticator(Action<User> onCompleted, Action<string> onError)
{
OAuth2Authenticator authenticator = new OAuth2Authenticator(
clientId,
null,
Scope,
new Uri(AuthorizeUrl),
new Uri(redirectUri),
new Uri(AccessTokenUrl),
null,
false);
authenticator.Completed += OnAuthCompleted;
authenticator.Error += OnAuthError;
OnCompleted = onCompleted;
OnError = onError;
return authenticator;
}
private async void OnAuthCompleted(object sender, AuthenticatorCompletedEventArgs e)
{
OAuth2Authenticator OAuth2Authenticator = sender as OAuth2Authenticator;
if (OAuth2Authenticator != null)
{
OAuth2Authenticator.Completed -= OnAuthCompleted;
OAuth2Authenticator.Error -= OnAuthError;
}
//User user = null;
if (e.IsAuthenticated)
{
// If the user is authenticated, request their basic user data from Google
// UserInfoUrl = https://www.googleapis.com/oauth2/v2/userinfo
var request = new OAuth2Request("GET", new Uri(UserInfoUrl), null, e.Account);
var response = await request.GetResponseAsync();
if (response != null)
{
// Deserialize the data and store it in the account store
// The users email address will be used to identify data in SimpleDB
string str = await response.GetResponseTextAsync();
JObject jobject = JObject.Parse(str);
User user = OAuthParser(jobject);
OnCompleted(user);
}
if (account != null)
{
store.Delete(account, App.AppName);
}
await store.SaveAsync(account = e.Account, App.AppName);
}
}
private void OnAuthError(object sender, AuthenticatorErrorEventArgs e)
{
OAuth2Authenticator OAuth2Authenticator = sender as OAuth2Authenticator;
if (OAuth2Authenticator != null)
{
OAuth2Authenticator.Completed -= OnAuthCompleted;
OAuth2Authenticator.Error -= OnAuthError;
}
OnError("Authentication error: " + e.Message);
}
private static User ParseGooglePlusResponse(JObject jobject)
{
try
{
User user = new User()
{
Email = jobject["email"].ToString(),
Pseudo = jobject["name"].ToString(),
Firstname = jobject["given_name"].ToString(),
Surname = jobject["family_name"].ToString(),
Image = jobject["picture"].ToString(),
Password = "girafe"
};
return user;
}
catch (Exception e)
{ Debug.WriteLine(e.ToString()); }
return null;
}
private static User ParseFacebookResponse(JObject jobject)
{
try
{
Debug.WriteLine(jobject);
User user = new User()
{
Email = jobject["email"].ToString(),
Pseudo = jobject["name"].ToString(),
Firstname = jobject["given_name"].ToString(),
Surname = jobject["family_name"].ToString(),
Image = jobject["picture"].ToString(),
Password = "girafe"
};
return user;
}
catch (Exception e)
{ Debug.WriteLine(e.ToString()); }
return null;
}
}
So, I'm using this class like that:
private void FacebookAuthConnection()
{
AuthenticationState.Authenticator = OAuthService.Facebook().Authenticator(OAuthLoginCompleted, OAuthLoginError);
Presenter.Login(AuthenticationState.Authenticator);
}
However, the problems are coming.. First, GooglePlus works, but I got an alert on my android phone that says "Chrome Custom Tabs Doesn't Close ...", so the application crashes with an empty stack trace... I searched on the web and the only thing I got is to turn false the last parameter of new OAuth2Authenticator();
, which doesn't work since google doesn't allow it from a webview...
So I was like, ok my code works, I get the user infos blablabla, let's try with facebook if it works from the native browser. However, I can't find the parameters URL...
Scope = "";
AuthorizeUrl = "";
AccessTokenUrl = "";
UserInfoUrl = "";
public_profile
https://m.facebook.com/dialog/oauth/
But what about the 2 others? I have them for Google+.
I'm really stuck and I feel like, each new seconds that passes, I get more and more frustrated...
Thank !
Edit
My actual values :
Scope = "email";
AuthorizeUrl = "https://www.facebook.com/v2.8/dialog/oauth";
AccessTokenUrl = "https://graph.facebook.com/oauth/access_token";
UserInfoUrl = "https://graph.facebook.com/me?fields=email,name,gender,picture\"";
clientId = "XXXX";
redirectUri = "http://www.facebook.com/connect/login_success.html";
Upvotes: 1
Views: 542
Reputation: 6502
Facebook allows authorization in embedded web views. So what it did is used external auth (in chrome tabs) for google+ (on some devices it just doesn't return to my app after authorization) - like you did. But for Facebook and VKontakte i used xamarin.auth in webviews, it's much less problematic, you have total control on everything but the login view design. Except on UWP ofc, where the total process is still buggy.
Answering the question regarding facebook right params for webview auth process:
// OAuth Facebook
// For Facebook login, configure at https://developers.facebook.com/apps
public static string FacebookClientId = "XXX";
public static string FacebookScope = "email";
public static string FacebookAuthorizeUrl = "https://www.facebook.com/v2.9/dialog/oauth";
public static string FacebookAccessTokenUrl = "https://graph.facebook.com/oauth/access_token";
Used as:
auth = new OAuth2Authenticator(
clientId: Constants.FacebookClientId,
scope: "email",
authorizeUrl: new Uri("https://www.facebook.com/v2.9/dialog/oauth"), // These values do not need changing
redirectUrl: new Uri("http://www.facebook.com/connect/login_success.html")// These values do not need changing
);
After what you get user's details with:
var request1 = new OAuth2Request("GET", new Uri("https://graph.facebook.com/me?fields=email,first_name,last_name,gender,picture"), null, eventArgs.Account);
Upvotes: 2