using Microsoft graph API i want user profile photo - microsoft-graph-api

Hi I am trying to get user photo, used
var tenantId = configuration.GetSection("AzureAd").GetSection("TenantId").Value;
var clientId = configuration.GetSection("AzureAd").GetSection("ClientId").Value;
var clientSecret = configuration.GetSection("AzureAd").GetSection("clientSecret").Value;
var InviteRedirectUrl = configuration.GetSection("AzureAd").GetSection("InviteRedirectUrl").Value;
var Instance = configuration.GetSection("AzureAd").GetSection("Instance").Value;
var URL = Instance + tenantId + "/v2.0";
var scopes = new string[] { "https://graph.microsoft.com/.default" };
var confidentialClient = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithAuthority(URL)
.WithClientSecret(clientSecret)
.Build();
GraphServiceClient graphServiceClient =
new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) =>
{
var authResult = await confidentialClient
.AcquireTokenForClient(scopes)
.ExecuteAsync();
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
})
);
Stream photo = await graphServiceClient.Me.Photo.Content.Request().GetAsync();
I got following error
Code: BadRequest Message: Current authenticated context is not valid for this request. This occurs when a request is made to an endpoint that requires user sign-in. For example, /me requires a signed-in user. Acquire a token on behalf of a user to make requests to these endpoints. Use the OAuth 2.0 authorization code flow for mobile and native apps and the OAuth 2.0 implicit flow for single-page web apps. Inner error:
how to solve it?

Related

How do I access Outlook365 mailbox using impersonation using .NET?

I'm using this code:
var cca = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithClientSecret(clientSecret)
.WithTenantId(tenantId)
.Build();
var ewsScopes = new [] { "https://outlook.office365.com/.default" };
var authResult = await cca.AcquireTokenForClient(ewsScopes).ExecuteAsync(cancellationToken);
var service = new ExchangeService
{
Credentials = new OAuthCredentials(authResult.AccessToken),
Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx"),
ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "mailbox#user.com"),
TraceListener = new TraceListener(),
TraceEnabled = true,
TraceFlags = TraceFlags.All
};
Folder inbox = Folder.Bind(service, WellKnownFolderName.Inbox);
The code throws a ServiceRequestException (403) on the last line, and trace logs contains the error:
x-ms-diagnostics: 2000008;reason="The token contains not enough scope to make this call.";error_category="invalid_grant"
Do I need to expand the ewsScopes? Or is this because I'm lacking the correct permissions in Azure? Which roles/permissions do I need?
Check the token your using in
Credentials = new OAuthCredentials(authResult.AccessToken),
in jwt.io
What you should see in the roles is
If you don't have that role it means your application registration isn't correct (eg you have added the delegate permission instead of Application permission which is a common mistake).

The given token is invalid error in EWS OAuth authentication when using personal account

I have to get the contacts from Exchange server from any account, so we have used the code from below link.
https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth
But it is not working for personal accounts, which is working fine for our organization account. So I have used AadAuthorityAudience property instead of TenantId and changed the scope from EWS.AccessAsUser.All to others. Now authentication got success but getting "The given token is invalid" error while using the token in ExchangeService.
var pcaOptions = new PublicClientApplicationOptions {
ClientId = "77xxxxxxxxxxx92324",
//TenantId = "7887xxxxxxxxxxxxx14",
RedirectUri = "https://login.live.com/oauth20_desktop.srf",
AadAuthorityAudience = AadAuthorityAudience.AzureAdAndPersonalMicrosoftAccount};
var pca = PublicClientApplicationBuilder.CreateWithApplicationOptions(pcaOptions).Build();
//var ewsScopes = new string[] { "https://outlook.office365.com/EWS.AccessAsUser.All" };
var ewsScopes = new string[] { "User.Read", "Contacts.ReadWrite.Shared" };
var authResult = await pca.AcquireTokenInteractive(ewsScopes).ExecuteAsync();
var ewsClient = new ExchangeService();
ewsClient.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
//ewsClient.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "araj#concord.net");
ewsClient.Credentials = new OAuthCredentials(authResult.AccessToken);
// Make an EWS call
var folders = ewsClient.FindFolders(WellKnownFolderName.MsgFolderRoot, new FolderView(10));
What am doing wrong here?
https://outlook.office365.com/EWS.AccessAsUser.All is the right scope to use. The scope is invalid for personal accounts since they're not supported by EWS.

Uploading a x509 cert to Application Manifest on Azure ADD or Microsoft Registration Portal

Sorry for the multiple post about the same issue!
I'm trying to upload a self signed sertificate to application manifest created on Microsoft Registration Portal but I have some issues which I don't completly understand why, According to this answer, it's very much possible to upload the certificate using DELEGATED PERMISSIONS however I don't see the reason why I can't use Application Permissions since I only need the AccessToken and I get that with the client_credential grant flow,
Below is the code that I have tried but when retrieving the token with client_credential grant flow, I get stuck att var application = activeDirectoryClient.Applications["ApplicationObjectId"].ExecuteAsync().Result;
and when trying to use the code given to my by Tom Sung in the previous post, the applications exits with error "must have client_credentil or client_assertion in request body"
this is the code that I have tried:
private static async Task<string> GetAppTokenAsync(string graphResourceId, string tenantId, string clientId, string userId)
{
string aadInstance = "https://login.microsoftonline.com/" + tenantId + "/oauth2/token";
var clientCredential = new ClientCredential(clientId, clientSecret);
AuthenticationContext authenticationContextt =
new AuthenticationContext($"https://login.microsoftonline.com/{tenantId}/oauth2/token");
AuthenticationResult result =
await authenticationContextt.AcquireTokenAsync(graphResourceId,
clientCredential);
//token is acquiered and gets stuck
var e = result.AccessToken;
//Tom Suns code
IPlatformParameters parameters = new PlatformParameters(PromptBehavior.SelectAccount);
AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance);
var authenticationResult = await authenticationContext.AcquireTokenAsync(graphResourceId, clientId, new Uri("http://localhost"), parameters, new UserIdentifier(userId, UserIdentifierType.UniqueId));
//exits with error
return authenticationResult.AccessToken;
}
try
{
var graphResourceId = "https://graph.windows.net";
var userId = "****";
//used to test if token is acquired
//var tokennn = await GetAppTokenAsync(graphResourceId, tenantID, ClientId, userId);
var servicePointUri = new Uri(graphResourceId);
var serviceRoot = new Uri(servicePointUri, tenant);
var activeDirectoryClient = new ActiveDirectoryClient(serviceRoot, async () => await GetAppTokenAsync(graphResourceId, tenantID, ClientId, userId));
AsymmetricKeyParameter myCAprivateKey = null;
//generate a root CA cert and obtain the privateKey
X509Certificate2 MyRootCAcert = CreateCertificateAuthorityCertificate("CN=OutlookIntegration", out myCAprivateKey);
//add CA cert to store
addCertToStore(MyRootCAcert, StoreName.Root, StoreLocation.LocalMachine);
var expirationDate = DateTime.Parse(MyRootCAcert.GetExpirationDateString()).ToUniversalTime();
var startDate = DateTime.Parse(MyRootCAcert.GetEffectiveDateString()).ToUniversalTime();
var binCert = MyRootCAcert.GetRawCertData();
var keyCredential = new KeyCredential
{
CustomKeyIdentifier = MyRootCAcert.GetCertHash(),
EndDate = expirationDate,
KeyId = Guid.NewGuid(),
StartDate = startDate,
Type = "AsymmetricX509Cert",
Usage = "Verify",
Value = binCert
};
//gets stuck here when using clientsecret grant type
var application = activeDirectoryClient.Applications["ApplicationObjectId"].ExecuteAsync().Result;
application.KeyCredentials.Add(keyCredential);
application.UpdateAsync().Wait();
}
catch (Exception exception)
{
Console.WriteLine(exception);
throw;
}
I am now completly stuck, Anyone have any idea why it doesn't work with Application Permissions or why it gets stuck at var application = activeDirectoryClient.Applications["ApplicationObjectId"].ExecuteAsync().Result;
Edit 1
is it because I have my app as a web app/API that uses username and password to authenticate?
Based on my test if we want to change the keyCredential, DELEGATED PERMISSIONS is required.
If we want to update Azure AD application other properties, we could use Application Permissions.
Reference:
Azure Active Directory developer glossary
"Delegated" permissions, which specify scope-based access using delegated authorization from the signed-in resource owner, are presented to the resource at run-time as "scp" claims in the client's access token.
"Application" permissions, which specify role-based access using the client application's credentials/identity, are presented to the resource at run-time as "roles" claims in the client's access token.

OpenIdConnectAuthenticationOptions and AcquireTokenByAuthorizationCodeAsync: Invalid JWT token

I'm trying to authorization code, and then hopefully a refresh token, with the OWIN OIDC middleware. However, I'm getting this error:
Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException: 'AADSTS50027: Invalid JWT token. AADSTS50027: Invalid JWT token. Token format not valid.
Trace ID: 8622dfea-05cd-4080-a52c-ec95a9593800
Correlation ID: 1cf57566-1e02-4856-a4bc-357d5b16ae8a
Note that the authentication part works: I do get the original IdToken back, and the SecurityTokenValidated Notifications event fires. The error above occurs on the "AcquireTokenByAuthorizationCodeAsync" line.
What I'm trying to do is use IdentityServer as an IdP inbetween Azure AD (upstream) and my client (downstream), and I need to capture the refresh token to validate against AAD when then client tries to use the downstream refresh token, so that I don't issue access tokens when the AAD user has been locked out or removed.
var authority = "https://login.microsoftonline.com/xxx.onmicrosoft.com/v2.0";
var clientId = "xxx-30f5-47c2-9ddb-b5fcfd583f96";
var redirectUri = "http://localhost:60546/oidcCallback";
var clientSecret = "c8RRB4DCUiXMPEotQh2jm2ArgpYAqUMjGhDRKuuJOxxx";
var oidc = new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
Caption = "OIDC",
ResponseType = OpenIdConnectResponseTypes.CodeIdToken,
RedirectUri = redirectUri,
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters() { ValidateIssuer = false },
SignInAsAuthenticationType = signInAsType,
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async e =>
{
var authContext = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(authority);
var result = await authContext.AcquireTokenByAuthorizationCodeAsync(e.ProtocolMessage.Code, new Uri(redirectUri), new ClientAssertion(clientId, clientSecret));
logger.Info(result.IdToken);
}
}
};
app.UseOpenIdConnectAuthentication(oidc);
Thanks!
One thing that I can see is wrong is that you should use ClientCredential, not ClientAssertion:
var result =
await authContext.AcquireTokenByAuthorizationCodeAsync(
e.ProtocolMessage.Code,
new Uri(redirectUri),
new ClientCredential(clientId, clientSecret));
And then the second thing. You are using ADAL, but seems like you are using the v2 endpoint. I assume you registered the app at apps.dev.microsoft.com?
In that case you should use MSAL (https://www.nuget.org/packages/Microsoft.Identity.Client).
The API for MSAL is a bit different, you use a class called ConfidentialClientApplication instead of AuthenticationContext (in this case). Here is a snippet from a sample app:
var cca = new ConfidentialClientApplication(clientId, redirectUri, new ClientCredential(appKey), userTokenCache, null);
string[] scopes = { "Mail.Read" };
AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, scopes);
Sample app: https://github.com/Azure-Samples/active-directory-dotnet-webapp-openidconnect-v2

How to remotely access the Identity Manager API hosted on IdentityServer3?

I have searched and found something but without full documentation here.
Could someone please give me a step by step explanation?
I have IdentityServer3 well-configured and I confirm that I can access the IdentityManager through the browser and manage users perfectly. Now, I need to manage users but from another custom made application. So I need to:
Login through the custom app
Manage users through the Idm API.
I have used the "ResourceOwner" grant and used the "idmgr" scope to get an access token: https://localhost:44376/ids/connect/token.
But when I use that token to access https://localhost:44376/idm/api/users?count=10&start=0, I get the message "Authorization has been denied for this request."
var client = new HttpClient();
var dic = new Dictionary<string, string>();
dic.Add("client_id", "mvc");
dic.Add("client_secret", "secret");
dic.Add("grant_type", "password");
dic.Add("scope", "openid profile");
dic.Add("username", "yazan#catec.ae");
dic.Add("password", "P#ssword1");
var content = new FormUrlEncodedContent(dic);
var msg = client.PostAsync("https://localhost:44383/identity/connect/token", content).Result.Content.ReadAsStringAsync().Result;
string token = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(msg).access_token;
var jwt = new JwtSecurityToken(token);
var identity = new ClaimsIdentity("ApplicationCookie", ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
foreach (var c in jwt.Claims)
{
var t = c.Type;
var v = c.Value;
identity.AddClaim(new Claim(t, v));
}
IAuthenticationManager authenticationManager = HttpContext.GetOwinContext().Authentication;
authenticationManager.SignOut("ApplicationCookie");
authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = false }, identity);
return Redirect("Index");

Resources