4

I am currently trying to use a REST service inside a xamarin.forms app.

To perform the authentication I use this code:

string consumerKey = "consumer_key";
string consumerSecret = "consumer_secret";
var requestTokenUrl = new Uri("https://service/oauth/request_token");
var authorizeUrl = new Uri("https://dservice/oauth/authorize");
var accessTokenUrl = new Uri("https://service/oauth/access_token");
var callbackUrl = new Uri("customprot://oauth1redirect");
authenticator = new Xamarin.Auth.OAuth1Authenticator(consumerKey, consumerSecret, requestTokenUrl, authorizeUrl, accessTokenUrl, callbackUrl, null, true);

authenticator.ShowErrors = true;
authenticator.Completed += Aut_Completed;

var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();

presenter.Completed += Presenter_Completed;
authenticator.Error += Authenticator_Error;

presenter.Login(authenticator);

Now, after authenticating the user will be redirected to customprot://oauth1redirect. To catch this redirection I added a new IntentFilter (for Android) like this:

 [Activity(Label = "OAuthLoginUrlSchemeInterceptorActivity", NoHistory = true, LaunchMode = LaunchMode.SingleTop)]
[IntentFilter(
 new[] { Intent.ActionView },
 Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
 DataSchemes = new[] { "customprot"},
 DataPathPrefix = "/oauth1redirect")]
public class OAuthLoginUrlSchemeInterceptorActivity : Activity
{
    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        // Convert Android.Net.Url to Uri
        var uri = new Uri(Intent.Data.ToString());

        // Load redirectUrl page
        Core.Controller.authenticator.OnPageLoading(uri);
        Core.Controller.authenticator.OnPageLoaded(uri);

        Finish();
    }
}

As far as I understood the documentation of xamarin.auth this will trigger the OAuth1Authenticator to parse the resulting url to get the authenticated user's credentials, and ultimatley triggering the Completed or Error event. But suprisingly nothing happens: no event is called or error raised. As this makes debugging harder, I do not really know how to solve this issue. Therefore, I am looking for suggestings about the cause of the issue and possible solutions, too.

Edit: Just to make this clearer: The OnCreate method of the intent is called, but executing the OnPageLoading method does not raise the Completed nor the Error event of the authenticator.

Edit2: here is the code of my callbacks (I created a breakpoint inside each of them, and the debugger does not break at them or raise an exception, so I am quite sure, that the callbacks are not called at all).

private static void Presenter_Completed(object sender, Xamarin.Auth.AuthenticatorCompletedEventArgs e)
{
    throw new NotImplementedException();
}

private static void Aut_Completed(object sender, Xamarin.Auth.AuthenticatorCompletedEventArgs e)
{
    throw new NotImplementedException();
}
zimmerrol
  • 4,872
  • 3
  • 22
  • 41
  • Can you please post your Aut_Completed callback for the authenticator.Completed. I tested my code with v1 and it worked fine. the authenticator.Completed was called first then after that the presenter completed. – TResponse Oct 17 '17 at 20:19
  • @don.coda See my edit. – zimmerrol Oct 18 '17 at 11:09

2 Answers2

1

This may only help future people (like me) that stumble on this question but perhaps not answer your particular issue. I was experiencing the same symptoms using the OAuth2Authenticator. I was capturing the redirect, calling OnPageLoading(), but then neither my completed or error events were firing.

The key for me was that it was only happening the 2nd time I called the Authenticator.

After digging through the Xamarin.Auth source, I realized that if HasCompleted is true when the authenticator calls OnSucceeded(), it simply returns without raising any events:

From Authenticator.cs

public void OnSucceeded(Account account)
{
    string msg = null;

    #if DEBUG
    string d = string.Join("  ;  ", account.Properties.Select(x => x.Key + "=" + x.Value));
    msg = String.Format("Authenticator.OnSucceded {0}", d);
    System.Diagnostics.Debug.WriteLine(msg);
    #endif

    if (HasCompleted)
    {
        return;
    }

    HasCompleted = true;

etc...

So, my issue was that I was keeping my authenticator instance around. Since HasCompleted is a private set property, I had to create a new authenticator instance and now it all works as expected.

Maybe I should have posted a new question and answered it. I'm sure the community will let me know.

0

I have also run into this issue but after managed to get this part working

I create my OAuth2Authenticatoras follows:

App.OAuth2Authenticator = new OAuth2Authenticator(
                        clientId: OAuthConstants.CLIENT_ID,
                        clientSecret: null,
                        scope: OAuthConstants.SCOPE,
                        authorizeUrl: new Uri(OAuthConstants.AUTHORIZE_URL),
                        accessTokenUrl: new Uri(OAuthConstants.ACCESS_TOKEN_URL),
                        redirectUrl: new Uri(OAuthConstants.REDIRECT_URL), //"com.something.myapp:/oauth2redirect" -- note I only have one /
                        getUsernameAsync: null,
                        isUsingNativeUI: true);

then in my Interceptor activity:

[Activity(Label = "GoogleAuthInterceptor")]
[IntentFilter
(
    actions: new[] { Intent.ActionView },
    Categories = new[]
    {
            Intent.CategoryDefault,
            Intent.CategoryBrowsable
    },
    DataSchemes = new[]
    {
        // First part of the redirect url (Package name)
        "com.something.myapp"
    },
    DataPaths = new[]
    {
        // Second part of the redirect url (Path)
        "/oauth2redirect"
    }
)]
public class GoogleAuthInterceptor: Activity
{
    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        // Create your application here
        Android.Net.Uri uri_android = Intent.Data;

        // Convert Android Url to C#/netxf/BCL System.Uri
        Uri uri_netfx = new Uri(uri_android.ToString());

        // Send the URI to the Authenticator for continuation
        App.OAuth2Authenticator?.OnPageLoading(uri_netfx);
       // remove your OnPageLoaded it results in an invalid_grant exception for me

        Finish();
    }
}

You can try changing your DataPathPrefix = "/oauth1redirect")] to

DataPaths = new[]
        {
            // Second part of the redirect url (Path)
            "/oauth1redirect"
        }

This successfully trigger the Completed event on the OAuth2Authenticator and then after that the one on the presenter

private async void OAuth2Authenticator_Completed(object sender, AuthenticatorCompletedEventArgs e)
{
    try
    {
        // UI presented, so it's up to us to dimiss it on Android
        // dismiss Activity with WebView or CustomTabs      
            if(e.IsAuthenticated)
        {
            App.Account = e.Account;
                var oAuthUser = await GetUserDetails();             
                // Add account to store
            AccountStore.Create().Save(App.Account, App.APP_NAME_KEY);

        }
        else
        {
            // The user is not authenticated
            // Show Alert user not found... or do new signup?
            await App.Notify("Invalid user.  Please try again");
        }
        }
    catch(Exception ex)
    {
        throw;
    }
}

At this stage I am redirected to the App.

I am currently trying to solve an issue where the presenter is not closed. It runs in the background even though the app is in the foreground and the user already authenticated. But this should hopefully help you solve your issue.

TResponse
  • 3,940
  • 7
  • 43
  • 63
  • Maybe I was not completely clear about my problem: the `OnCreate` method of the intent is called, but executing the `OnPageLoading` method does not raise the `Completed` or the `Errors` event of the authenticator. – zimmerrol Oct 14 '17 at 09:41
  • Ok i understand now. Have you tried using the OAuth2Authenticator authenticator? Or do you need the version 1 specifically? – TResponse Oct 14 '17 at 18:35
  • Yes. Sadly the service is only supporting version 1. – zimmerrol Oct 14 '17 at 18:47