AcquireTokenAsync expiring after 1 or 2 hours - c#

I am trying to call AcquireTokenAsync it is working properly but after sometime it is not responding and it is not providing any result.
please refer the below code how to solve my issue
public static async Task<string> GetToken(string authority, string resource, string scope)
{
var authContext = new AuthenticationContext(authority);
ClientCredential clientCred = new ClientCredential(WebConfigurationManager.AppSettings["ClientId"],
WebConfigurationManager.AppSettings["ClientSecret"]);
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
if (result == null)
throw new InvalidOperationException("Failed to obtain the JWT token");
return result.AccessToken;
}
public static string GetKeyVaultSecret(string secretName)
{
try
{
var secretUri = WebConfigurationManager.AppSettings["SecretUri"];
var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetToken));
var secret = kv.GetSecretAsync(secretUri, secretName).Result;
return secret.Value;
}
catch(Exception ex)
{
return null;
}
}

For access token, the default time is 1 hour. After 1 hour, the client must use the refresh token to (usually silently) acquire a new refresh token and access token.
You can change access token lifetime to the maximum to one day with this tutorial.
New-AzureADPolicy -Definition #('{"TokenLifetimePolicy":{"Version":1,"AccessTokenLifetime":"24:00:00","MaxAgeSessionSingleFactor":"02:00:00"}}') -DisplayName "WebPolicyScenario" -IsOrganizationDefault $false -Type "TokenLifetimePolicy"
For more details about token lifetime you can refer to this article.

Related

Calling MS Graph API has error CompactToken parsing failed with error code: 80049217

We implement to get the phone numbers being used in MFA of the signed-in user. We use password grant flow where we have a service account(with Global admin role) that will call MS Graph API on behalf of the user.
We are able to get the access token. However, when making a call to MS Graph encounters the error below.
Error:
ServiceException: Code: InvalidAuthenticationToken
Message: CompactToken parsing failed with error code: 80049217
MS Graph API call:
MicrosoftGraphClientSDK client = new MicrosoftGraphClientSDK();
var graphClient = client.GetAuthenticatedClient();
// Error encountered here:
var phones = await graphClient.Me.Authentication.PhoneMethods[{objectiD of the user}].Request().GetAsync();
This is how we get the access token in GetAuthenticatedClient
public MicrosoftGraphClientSDK()
{
_app_public = PublicClientApplicationBuilder.Create(clientID)
.WithAuthority("https://login.microsoftonline.com/{tenantID}")
.Build();
}
public Beta.GraphServiceClient GetAuthenticatedClient()
{
var accessToken = GetUserAccessTokenAsync();
var delegateAuthProvider = new DelegateAuthenticationProvider((requestMessage) =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.ToString());
return Task.FromResult(0);
});
_graphClient = new Beta.GraphServiceClient(delegateAuthProvider);
return _graphClient;
}
public async Task<string> GetUserAccessTokenAsync()
{
AuthenticationResult result;
var accounts = await _app_public.GetAccountsAsync();
if (accounts.Any())
{
result = await _app_public.AcquireTokenSilent(_scopes, accounts.FirstOrDefault())
.ExecuteAsync();
}
else
{
SecureString password = new SecureString();
foreach (char c in pass)
password.AppendChar(c);
result = await _app_public
.AcquireTokenByUsernamePassword(_scopes, username, password)
.ExecuteAsync();
}
return result.AccessToken;
}
I have search online about the error but could not get figure out the solution.
I appreciate your response. Thanks.

Oauth token accessing

I want to get access token to use it to fetch email from outlook using microsoft graph api. My application will be Console based c# application which will run automatically after every 20 min and will fetch the email.
I am new to c# as well as microsoft graph, this is my first task related to these technology.
Problem is:
When i tried to fetch token using client_Credentials i was successfully able to do so, but now that token is expired i want to get new token and if I try to generate new token it is returning the expired one only.
Relevant code:
result = await context.AcquireTokenAsync(resourceUri, clientCredential);
Using AcquireTokenSilentAsync method return as error:
"Failed to acquire token silently as no token was found in the cache. Call method AcquireToken."
Relevant code:
result = await authContext.AcquireTokenSilentAsync(resourceUri, clientId);
My questions:
Is accessing token using client credential is correct way to fulfill my need?
I have read that using client_Credentials we do not need refresh_token, every time we try to connect we will get new token.
How to get new token every time I want to connect?
Any extra suggestion about how to approach to my main objective which are not asked in question would be dearly welcomed.
I'm attaching my code sample:
static async Task getAccessToken()
{
authContext = new AuthenticationContext("https://login.microsoftonline.com/<tenantId>");
try
{
result = await authContext.AcquireTokenSilentAsync(resourceUri, clientId);
}
catch (Exception ex)
{
Console.WriteLine(ex);
try
{
result = await authContext.AcquireTokenAsync(resourceUri, clientCredential);
Console.WriteLine("" + result.AccessToken+"\n\n");
}
catch (Exception e)
{
Console.WriteLine("\n AcquireTokenAsync failed\n");
Console.WriteLine(""+e);
}
}
if (result == null)
{
Console.WriteLine("Canceling attempt to get access token.\n");
return;
}
Console.WriteLine(result.AccessToken);
}
You're mixing a two different OAuth flows (Authorization Code and Client Credentials). You should only need to call AcquireTokenAsync with the correct credentials. Whenever you need a new token (each token lives about an hour), you re-execute this method to get a new token:
static async Task<AuthenticationResult> getAccessToken()
{
ClientCredential clientCredential = new ClientCredential("YOUR_APP_ID", "YOUR_APP_SECRET");
AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/YOUR_TENANT_ID");
AuthenticationResult result = null;
try
{
result = await authContext.AcquireTokenAsync("https://graph.microsoft.com", clientCredential);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
if (result == null)
Console.WriteLine("Canceling attempt to get access token.");
else
Console.WriteLine(result.AccessToken);
return result;
}

Using Microsoft Graph to get on premises Mail using C#

I am trying to get my mail on premises using GraphServiceClient. I am getting the token from Microsoft online account then use that token to get my emails. But because my mails are on premises I cannot access the as it throws the following error "code": "ResourceNotFound", "message": "Resource could not be discovered.". So how can I change my code to use the same token I get from online to on premises Mail using GraphServiceClient (if it is possible).
public async Task<ActionResult> Inbox()
{
string token = await GetAccessToken();
if (string.IsNullOrEmpty(token))
{
// If there's no token in the session, redirect to Home
return Redirect("/");
}
GraphServiceClient client = new GraphServiceClient(
new DelegateAuthenticationProvider(
(requestMessage) =>
{
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", token);
return Task.FromResult(0);
}));
var mailResults = await
client.Me.MailFolders.Inbox.Messages.Request()
.OrderBy("receivedDateTime DESC")
.Select("subject,receivedDateTime,from")
.Top(10)
.GetAsync();
return View(mailResults.CurrentPage);
}
public async Task<string> GetAccessToken()
{
string accessToken = null;
// Load the app config from web.config
string appId = ConfigurationManager.AppSettings["ida:AppId"];
string appPassword = ConfigurationManager.AppSettings["ida:AppPassword"];
string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
string[] scopes = ConfigurationManager.AppSettings["ida:AppScopes"]
.Replace(' ', ',').Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
// Get the current user's ID
string userId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
if (!string.IsNullOrEmpty(userId))
{
// Get the user's token cache
SessionTokenCache tokenCache = new SessionTokenCache(userId, HttpContext);
ConfidentialClientApplication cca = new ConfidentialClientApplication(
appId, redirectUri, new ClientCredential(appPassword), tokenCache.GetMsalCacheInstance(), null);
// Call AcquireTokenSilentAsync, which will return the cached
// access token if it has not expired. If it has expired, it will
// handle using the refresh token to get a new one.
IEnumerable<IAccount> accounts = await cca.GetAccountsAsync();
IAccount fisrtAccount = accounts.FirstOrDefault();
AuthenticationResult result = await cca.AcquireTokenSilentAsync(scopes, fisrtAccount);
accessToken = result.AccessToken;
}
return accessToken;
}
By default you can't access any on-prem information with the Microsoft Graph. The only exception to that is a preview feature in Exchange 2016 that allows you to access Calendar, Mail and Contact items transparently.
This feature has a number of infrastructure pre-requisites so I suggest you connect with your infrastructure team first to validate those. Once those pre-requisites are in place, you should not have to change any code from the application's perspective to access the content. Keep in mind this is a preview feature, so not supported for production workloads.

Azure - Token is not renewed (Authentication_ExpiredToken). Why?

I have a C# Azure Web Application that accesses Azure Active Directory to get data from users and groups.
After 1h of activity, I get the following error:
{"odata.error":{"code":"Authentication_ExpiredToken","message":{"lang":"en","value":"Your access token has expired. Please renew it before submitting the request."},"date":"2018-03-16T16:17:59","requestId":"cfa18a20-3c2c-4806-ac36-9d4e9ba7738c","values":null}}
Here is my method to get a ActiveDirectoryClient:
using Microsoft.Azure.ActiveDirectory.GraphClient;
using Microsoft.Azure.ActiveDirectory.GraphClient.Extensions;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
private ActiveDirectoryClient CreateGraphClient()
{
string tenantId = WebConfigurationManager.AppSettings["ida:TenantId"],
applicationId = WebConfigurationManager.AppSettings["ida:ClientId"],
secret = WebConfigurationManager.AppSettings["ida:ClientSecret"],
authority = WebConfigurationManager.AppSettings["ida:AADInstance"] + tenantId,
resrouce = "https://graph.windows.net",
token = string.Empty;
ClientCredential credential = new ClientCredential(applicationId, secret);
AuthenticationContext authContext = new AuthenticationContext(authority);
try
{
token = authContext.AcquireTokenAsync(resrouce, credential).Result.AccessToken;
}
catch (Exception)
{
token = authContext.AcquireTokenSilentAsync(resrouce, credential.ClientId).Result.AccessToken;
}
Uri baseServiceUri = new Uri(resrouce);
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(new Uri(baseServiceUri, tenantId), async () => await Task.FromResult(token));
return activeDirectoryClient;
}
I think the server should refresh the token but it's not happenning. I'm using ADAL 3.x so the 'refresh_token' doesn't exist anymore (I guess).
I know this try/catch is not the way but it was a test.
Any help?

How to access secret key from Azure vault

I have followed the official document and developed the code, but it's not working. I have to get the secret key stored in the vault.
When I debug, it just stops at the mentioned step and doesn't go further. I also tried without debugging. It's the same. Are there any more settings/permissions to make.
private void EncryptFields()
{
string publicKey = GetAzureVaultSecret().Result;
}
public static async Task<string> GetAzureVaultSecret()
{
var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetAzureVaultAccessToken));
var secret = await kv.GetSecretAsync(GlobalConstants.AzureVaultURLSecretURI);
return secret.Value;
}
public static async Task<string> GetAzureVaultAccessToken(string authority, string resource, string scope)
{
var authContext = new AuthenticationContext(authority);
ClientCredential clientCred = new ClientCredential(GlobalConstants.AzureVaultClientId, GlobalConstants.AzureVaultClientSecret);
//STOPS AT THE BELOW STEP AND NOTHING HAPPENS
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the token");
}
return result.AccessToken;
}
Log:
ManagedPoolThread #3 00:23:46 WARN Memory usage exceeded the
MemoryMonitor threshold. ManagedPoolThread #3 00:23:46 WARN Memory
usage: 3,21,95,91,168 ManagedPoolThread #3 00:23:46 WARN Number of
suppressed logs due to the minimum time between log entries: 10

Categories

Resources