0
votes

The goal it use Graph API to send an email. I am able to get the Authorization token by using the below code - https://login.microsoftonline.com/Some_Tenant_ID/oauth2/v2.0/authorize?client_id=SOME_Client_ID&response_type=code&redirect_uri=https://localhost&response_mode=query&scope=offline_access%20user.read%20mail.read&state=12345

The scope is user.read and mail.send with offline access. Now from using this authorization code, I want to get the refresh token. From my understanding this should work without any problem but for some reason the code is breaking at this line var httpResponse = (HttpWebResponse)request.GetResponse(); and I not sure why.

The exception code error 400 Bad Request. my console output.

enter image description here

Can any one help me here and is there another way to get the Access token and/or refresh token from Authorization token. the end goal is to send email from graph API.

string tokenUrl = "https://login.microsoftonline.com/myAppTenantID/oauth2/token";
//string tokenUrl = "https://login.microsoftonline.com/myAppTenantID/oauth2/v2.0/token"; I have tried this URL too
string grant_type= "authorization_code";
string ClientID = "MyAppClientID";
string Auth_Code = "My Auth Code";
string RedirectURI = "https://localhost";
string ClientSecret = "my App secret";
Dictionary<string, string> res_dic = null;
string TargetURL = String.Format(tokenUrl);
var request = (System.Net.HttpWebRequest)WebRequest.Create(TargetURL);
request.ContentType = "application/x-www-form-urlencoded";
string RefreshToken = null;


string requestBody = String.Format(@"client_id={0}&scope=user.read%20mail.read&code={1}&redirect_uri={2}&grant_type=authorization_code&client_secret={3}", ClientID, Auth_Code,RedirectURI, ClientSecret);
request.Method = "POST";
using (var streamwriter = new StreamWriter(request.GetRequestStream()))
{
    Console.WriteLine("stage 0....");
    streamwriter.Write(requestBody);
    streamwriter.Flush();
    streamwriter.Close();
}
try
{
    Console.WriteLine("stage 1....");
    //Console.WriteLine("prting response"+ (HttpWebResponse)request.GetResponse());
    var httpResponse = (HttpWebResponse)request.GetResponse();
    Console.WriteLine("Stage 2....");
    using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
    {
        Console.WriteLine("Stage 3");
        string Result = streamReader.ReadToEnd();
        string StatusCode = httpResponse.StatusCode.ToString();
        res_dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(Result);
    }
}
catch (WebException ex)
{
    Console.WriteLine("stage 4");
    string ErrorMessage = ex.Message.ToString();
    Console.WriteLine(ErrorMessage);
}
RefreshToken = res_dic["refresh_token"].ToString();

}
1

1 Answers

0
votes

This is better for you to debug for full error message, there are many situations where this error occurs.

The scope in your code needs to add offline_access because refresh_token will be only provided if offline_access scope is requested.

You could use SDK. Code sample here:

string[] scopes = new string[] { "", "" };

IConfidentialClientApplication app = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithRedirectUri(redirectUri)
    .WithClientSecret(clientSecret)
    .WithAuthority(authority)
    .Build();

AuthorizationCodeProvider auth = new AuthorizationCodeProvider(app, scopes);

GraphServiceClient graphServiceClient = new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) => {

    // Retrieve an access token for Microsoft Graph (gets a fresh token if needed).
    var authResult = await app.AcquireTokenByAuthorizationCode(scopes, auth_code).ExecuteAsync();

    // Add the access token in the Authorization header of the API request.
    requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
    
})
);

And this API is used for sending mail, you need to add Mail.Send permission first.

var message = new Message
{
    Subject = "Meet for lunch?",
    Body = new ItemBody
    {
        ContentType = BodyType.Text,
        Content = "The new cafeteria is open."
    },
    ToRecipients = new List<Recipient>()
    {
        new Recipient
        {
            EmailAddress = new EmailAddress
            {
                Address = "[email protected]"
            }
        }
    },
    CcRecipients = new List<Recipient>()
    {
        new Recipient
        {
            EmailAddress = new EmailAddress
            {
                Address = "[email protected]"
            }
        }
    }
};

var saveToSentItems = false;

await graphClient.Me
    .SendMail(message,saveToSentItems)
    .Request()
    .PostAsync();