MS Graph API Blocking Credentials on one call, but not another - c#

While expanding our WPF Apps emailing functions to include larger attachments, we went from using the MS GRAPH API endpoint me/sendMail to send emails:
https://graph.microsoft.com/v1.0/me/sendMail
to using the me/messages endpoint to create a draft so that we could create an upload session to that draft so that we could upload larger attachments (pdf reports)
https://graph.microsoft.com/v1.0/me/messages
We are acquiring tokens via MSAL for both. However, when using the second method, we receive the following response:
"ErrorAccessDenied"
"Access is denied. Check credentials and try again."
Our expectation was that those two endpoints wouldn't have different credentialing requirements. Our organization's AzureAD accounts are federated delegate, so the only flow we can use is interactive Authorization Code -- so we are calling into MSAL to get the AzureAD token for both endpoints.

The endpoint for creating a draft message
POST /me/messages
requires Mail.ReadWrite permission. While endpoints for sending mail
POST /me/messages/{id}/send
POST /me/sendMail
require Mail.Send.
Adding Mail.ReadWrite permission should resolve the error.

Related

IdentityServer4 Getting Claims using Reference Token with Client_Credentials

I have an identity server implementation that works perfectively with jwt tokens and two different clients that access it.
Mr Console authenticates using client_credentials
Ms Website authenticates using pkce
In both cases when using jwt tokens I can get the claims with only one issue. The size of the token is getting out of hand and we'd like to use reference tokens instead.
I changed the token type from Jwt to Reference and can now get the claims for Ms Website by calling the user info endpoint and passing in the reference token. Great!
The problem I have is that I cannot seem to get the claims for Mr Console.
I cannot call the user info endpoint because it expects a user and throws an error "Token contains no sub claim" - which it wouldn't as I'm using client credentials.
I cannot call the introspective endpoint as it appears to only be available to internal apis and fails with the error "API unauthorized to call introspection endpoint".
How can I get the claims from within my client console application when provided with a reference token and not a jwt? Is there a way?
Thanks
Because you are using the client credentials flow you have no user claims available.
However you have Client claims that you can use instead, have you considered to use those instead of userclaims?

"Either scp or roles claim need to be present in the token" when using app permissions to access my OneDrive

I have a web application that allows me to sign in to my OneDrive account using delegated permissions to authorize the app to browse my drive files on my behalf. I'm now trying to build a server-side job that needs to work with these files and therefore needs application permissions granted with admin consent.
I've followed various instructions to achieve this, but no matter what I do I keep getting this 403 error:
Either scp or roles claim need to be present in the token
The application I've registered in Azure portal has the application permission Files.Read.All and I've granted admin consent. I'm obtaining my access token as follows:
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create("<client-id>")
.WithClientSecret("<secret>")
.WithAuthority(new Uri("https://login.microsoftonline.com/common"))
var apiUrl = "https://graph.microsoft.com/";
string[] scopes = { $"{apiUrl}.default" };
result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
I'm then using the returned token to request "{apiUrl}v1.0/drives/<my-drive-id>/items/<drive-item-id>"
And this is where I get the access denied. Clearly the API expects my token to have either a roles claim or an scp claim.
After reading this related post on SO I did wonder if the problem is related to the fact I'm using the same app registration for the front end and back end operations (so it has a mix of delegated and application permissions) but I tried creating a new app registration with only the application permissions and it was the same error.
Also, that post suggests I should expect to see either and scp or a roles claim in my token (depending on choice of auth flow) but I get neither of these claims. That led me to this other SO post which suggests I need to explicitly include roles in my access token, but roles isn't listed as an optional claim in the Token configuration blade of the app registration.
So I'm stuck. Can anyone help?
UPDATE 1
I've tried constructing the auth request manually now using a POST to https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token and a form body that includes grant_type=client_credentials and now I'm finding the roles claim is returned in the token. So I guess the ConfidentialClientApplicationBuilder wasn't building a client credentials auth request as I had assumed. However, when I use this token to make the above Graph API request for a drive item I get the error:
Tenant does not have a SPO license
When I've encountered this before I've been told to use common instead of my tenant ID. However, when I make that change in this case I'm again left with a token that doesn't have a roles claim.
The absence of the roles claim indicates that you app (or service) hasn't been granted any application permissions (i.e. app roles) for the API (in this case, Microsoft Graph), in the tenant where the token request is being made.
You need to ensure the the application permissions (app roles) you expect the app to use to make the API call have been granted in the tenant where you are making the API call.

Token access blocked when posting request from published Azure function

I am struggling to get a token from "https://login.microsoftonline.com/common/oauth2/token" with an Azure function by a post-request. The token will give permissions to access SharePoint though CSOM. Here is my code snippet with the post request:
var clientId = defaultAADAppId;
var body = $"resource={resource}&client_id={clientId}&grant_type=password&username={HttpUtility.UrlEncode(username)}&password={HttpUtility.UrlEncode(password)}";
using (var stringContent = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded"))
{
var result = await httpClient.PostAsync(tokenEndpoint, stringContent);
var tokenResult = JsonSerializer.Deserialize<JsonElement>(result);
var token = tokenResult.GetProperty("access_token").GetString();
}
When testing locally, both when running the function in Visual studio and when I try with Postman, I am able to achieve an access token. However, as soon as I publish the function to my Function app in Azure I receive the following error message:
"AADSTS53003: Access has been blocked by Conditional Access policies. The access policy does not allow token issuance"
I have enabled an app registration in the portal and as mentioned, it all works fine until I publish everything to Azure.
Any ideas on how to solve this?
I got it to work now. First of all I reviewed the CA policies as #CaseyCrookston suggested. What I found out was that our CA policies blocked calls outside the country we operate from. However, the calls from the App registration/Azure function were registered from the Azure data centre location and thus, blocked by our CA policies. When running them locally the calls where registered in my country and therefore no errors were showing while debugging.
My first step was trying to add my Client app to the CA policy, which was not possible. The client/secret authentication that I used based on the suggestions in this CSOM guide by Microsoft prevented the App registration to be whitelisted from the CA policies (Github issue).
Based on this I had to change the authentication to a Certificate-based authentication as suggested here: Access token request with a certificate and here: SO answer. With this I was able to whitelist the App registration in the CA policies and successfully authenticate to the Sharepoint CSOM.
As the error message says, your app is blocked by CA policy. Possible causes can be unknown client app, blocking external IP addresses, etc.
You can perform one of the below workarounds:
Add your Client app to your CA policy.
I wouldn’t recommend this because this affects your security - if you take the risk you could exclude the “Microsoft Azure Management” from your CA policy which blocks unknown clients / requires device state and still protect the sign-in with MFA.
A better approach is to use another OAuth 2.0 and OpenID connect flow like the delegated flow where you sign-in directly within the app, if possible.

How to validate oauth token in my application using load balancer?

I have an api project configured with oauth for authentication. since the application uses load balancer to manage multiple requests, let's assume (server-1 ad server-2).
first request with valid credentials => server 1 (here token was generated)
second request with token included in header => server 2
now second request getting "Authorization Denied". How to handle this scenario?
Guess you are looking for something like vouch-proxy.
Here some useful links:
Article: https://medium.com/lasso/use-nginx-and-lasso-to-add-google-authentication-to-any-application-d3a8a7f073dd
Project: https://github.com/vouch/vouch-proxy

Active Directory Authentication Exception (AADSTS90027) with Azure AD

I have a native client application which is obtaining an OAuth2 token for Active Directory authorization. It will then use that token to communicate with a secure Web API server where certain areas of the API are secured using the [Authorize] attribute. The server is also registered with Azure AD and can properly authorize requests through AD.
When I try to get the token, I get the following exception on Line 2 of the code below:
Additional information: invalid_request: AADSTS90027: The client '<Client GUID>' and resource 'https://abccompany.com/MyApplication.Server' identify the same application.
Here is my code which I am running in the native client (just on a button press as a test, for now). Obviously the GUID and company names have been obfuscated.
AuthenticationContext ac = new AuthenticationContext("https://login.windows.net/abccompany.com");
AuthenticationResult ar = ac.AcquireToken("https://abccompany.com/MyApplication.Server", "<Client GUID>", new Uri("https://localhost:44300/secure"), PromptBehavior.Auto);
I made sure the redirect existed in Azure in the application configuration (otherwise there would have been a redirect error instead). What does the error mean?
You seem to be using the clientId of the WebAPI where you need to supply the clientId of the client app. Please register a separate 'Native client application' in Azure AD representing the client app.
The following topic explains the protocol flow and how to register WebAPIs in Azure AD such that users from multiple AD tenants can use that API: http://msdn.microsoft.com/en-us/library/azure/dn499820.aspx#BKMK_Native
The following samples should see you through:
Single tenant WebAPI: https://github.com/AzureADSamples/NativeClient-WindowsStore
Multi-tenant WebAPI: https://github.com/AzureADSamples/NativeClient-WebAPI-MultiTenant-WindowsStore
Hope this helps.
ps: Azure AD doesn't issue a token when the client and resource are the same application. In your case they should indeed be different and resource clientid (issued to a confidential client) should not be used as a public client - however for service to service scenarios, it can be argued that issuing tokens to self should be allowed - this is something we are looking into.

Categories