简体   繁体   中英

How can I get a token from ADAL in Xamarin.iOS?

I want to get a token from ADAL to authenticate a specific server call.

I have tried to use this code:

var authorityUrl = string.Format(@"https://login.microsoftonline.com/{0}/oauth2/token", AadInstance);
var context = new AuthenticationContext(authorityUrl);
var credential = new ClientCredential(ClientId, ClientSecret);
var authenticationResult = context.AcquireTokenAsync(RemoteClientId, credential).Result;
return authenticationResult.AccessToken;

But I get this in the logs:

AcquireTokenHandlerBase.cs: === Token Acquisition started:
    Authority: https://login.microsoftonline.com/f9e55202-63c0-4821-9fc7-e38eb5bc3a08/oauth2/token/
    Resource: 80d147c1-0b9a-48e0-8a62-1dc82890e98e
    ClientId: cab18d6f-3edc-446b-a071-45b28b192f0b
    CacheType: null
    Authentication Target: Client

TokenCache.cs: Looking up cache for a token...
TokenCache.cs: No matching token was found in the cache
AcquireTokenHandlerBase.cs: System.NullReferenceException: Object reference not set to an instance of an object
  at Microsoft.IdentityModel.Clients.ActiveDirectory.BrokerHelper.get_CanInvokeBroker () [0x0000c] in <f671779d8b3b49399b31bf519785e86e>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase+<RunAsync>d__55.MoveNext () [0x00389] in <e4081d9da4634689910019c82c03f3e7>:0

I have no idea what might be wrong with this, as this same code works as expected on the Android app, while it doesn't work on the iOS version.

There's a few funny things in your code. First and foremost, iOS and Android apps are public clients and thus can't properly protect a client secret. You should never store a client secret in your app. As such, the client credentials flow isn't meant or possible for this scenario, but rather server to server app authentication. This could be the root reason for your error.

Here's a great sample of how to build a Xamarin app using ADAL for all Android, iOS, Win Desktop, Windows Universal. I highly recommend following the pattern set forth here.

I ended up implementing the call myself:

public async Task<string> GetADALToken(string aadInstance, string clientId, string clientSecret, string remoteClientId)
{
    string body = $"resource={remoteClientId}&client_id={clientId}&client_secret={clientSecret}&grant_type=client_credentials";
    HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, $"https://login.microsoftonline.com/{aadInstance}/oauth2/token");

    byte[] byteArray = Encoding.UTF8.GetBytes(body);
    var content = new ByteArrayContent(byteArray);
    // set content type
    content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
    message.Content = content;

    message.Headers.Add("Accept", "application/json");

    HttpResponseMessage result = null;
    try
    {
        result = await _adalClient.SendAsync(message);
        result.EnsureSuccessStatusCode();
        var v = await result.Content.ReadAsStringAsync();
        return v;
    }
    catch (HttpRequestException reqExecption)
    {
        Log(reqExecption);
        if (result != null)
        {
            return "error " + await result.Content.ReadAsStringAsync();
        }
        return "error " + reqExecption.Message;
    }
    catch (Exception ex)
    {
        Log(ex);
        return "error " + ex.Message;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM