Julius Depulla
Julius Depulla

Reputation: 1633

How do I get Azure AD OAuth2 Access Token and Refresh token for Daemon or Server to C# ASP.NET Web API

I have implemented an Azure AD OAuth2 Daemon or Server to ASP.NET Web API. However I only receive an access token which is the property on the AuthenticationResult. See implementation below.

    public IHttpActionResult GetAccessToken(string clientId, string clientkey)
    {
        AuthenticationContext authContext = new AuthenticationContext(authority);
        ClientCredential clientCredential = new ClientCredential(clientId, clientkey);
        AuthenticationResult authenticationResult = authContext.AcquireTokenAsync(resourceUri, clientCredential).Result;
        Authorisation authorisation = new Authorisation {access_token = authenticationResult.AccessToken,
                                                token_type = authenticationResult.AccessTokenType,
                                                expires_on = authenticationResult.ExpiresOn };

        return Ok(authorisation);
    }   

This returns only access token. I would like an implementation, a Daemon or Server implementation that returns both access token and refresh token. Have your seen or done similar implementation. Any useful links to an example are welcome.

Upvotes: 6

Views: 19951

Answers (3)

Julius Depulla
Julius Depulla

Reputation: 1633

When I posted this question, this was the answer I was looking for, please see screen shot below for expected result and c# console solution. Having found the solution, it is worth sharing it here, may be useful to someone some day

C# console app code to achieve expected result in the postman screen shot below

using System;
using System.Collections.Generic;
using System.Net.Http;

namespace AzureADTokenApp
{
    class Program
    {
        static void Main(string[] args)
        {

            var client = new HttpClient();
            var uri = "https://login.microsoftonline.com/<tenant-name>.onmicrosoft.com/oauth2/token?api-version=1.0";
            var pairs = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("resource", "https://graph.microsoft.com"),
                new KeyValuePair<string, string>("client_id", "<azure ad client id e.g. 9b864-a5e6-4f0d-b155-1f53a6c78>"),
                new KeyValuePair<string, string>("client_secret", "<azure ad client secret e.g. MTMiXaO1P9HnhSawdXWmcnuQ="),
                new KeyValuePair<string, string>("grant_type", "password"),
                new KeyValuePair<string, string>("username", "<azure ad user e.g. [email protected]>"),
                new KeyValuePair<string, string>("password", "<azure ad user password e.g. Pa$$word01>"),
                new KeyValuePair<string, string>("scope", "openid")
             };

            var content = new FormUrlEncodedContent(pairs);

            var response = client.PostAsync(uri, content).Result;

            string result = string.Empty;

            if (response.IsSuccessStatusCode)
            {

                result = response.Content.ReadAsStringAsync().Result;
            }

            Console.WriteLine(result);
            Console.ReadLine();
        }
    }
}

Screenshot from Postman - Expected Result. You will have same result in console except is less readable

enter image description here

Upvotes: 12

Fei Xue
Fei Xue

Reputation: 14649

There is no need to use the refresh token to redeem to access token manually if you were developing with ADAL v3.

In this scenario, we should use the AcquireTokenSilentAsync and catch the exception. After the access_token is expired, we should re-initialize AuthenticationContext and call the AcquireTokenAsync again to send the request to acquire the access_token.

Here is a code sample for your reference:

class Program
{
    static string authority = "https://login.microsoftonline.com/adfei.onmicrosoft.com";
    static string resrouce = "https://graph.microsoft.com";
    static string clientId = "";
    static string secret = "";
    static ClientCredential credential = new ClientCredential(clientId, secret);
    static AuthenticationContext authContext = new AuthenticationContext(authority);
    static void Main(string[] args)
    {
        while (true)
        {
            var client = new GraphServiceClient(new DelegateAuthenticationProvider(request =>
            {
                request.Headers.Authorization = new AuthenticationHeaderValue("bearer", GetAccessToken());
                return Task.FromResult(0);
            }));

            var users = client.Users.Request().GetAsync().Result.CurrentPage;
            foreach (var user in users)
            {
                Console.WriteLine(user.DisplayName);
            }          
            Thread.Sleep(1000 * 60 * 5);
        }
        Console.Read();
    }

    static string GetAccessToken()
    {
        try
        {
            var token = authContext.AcquireTokenAsync(resrouce, credential).Result.AccessToken;             
            return token;
        }
        catch (Exception ex)
        {
            authContext = new AuthenticationContext(authority);
            return GetAccessToken();
        }
    }

Upvotes: 1

andresm53
andresm53

Reputation: 2083

You are using the client credentials flow. In that flow, a refresh token should not be included https://www.rfc-editor.org/rfc/rfc6749#section-4.4.3. Also it looks like you are using ADAL v3, which anyways doesn't return refresh tokens (by design), but it uses them automatically for you. More info here http://www.cloudidentity.com/blog/2015/08/13/adal-3-didnt-return-refresh-tokens-for-5-months-and-nobody-noticed/

Upvotes: 1

Related Questions