AADSTS700023: Client assertion audience claim does not match Realm issuer error in ConfidentialClientApplication - msal

I'm successfully getting an authorization code with a call to https://login.microsoftonline.com/common/oauth2/v2.0/authorize
but when I try to acquire the token with that code with a call to
confidentialClientApplication.AcquireTokenByAuthorizationCodeAsync(code, new[] {"files.read.all"});
I get an error of
AADSTS700023: Client assertion audience claim does not match Realm issuer
I'm creating the ConfidentialClientApplication with a call to:
new ConfidentialClientApplication("Same client id as the authorize call", "https://login.microsoftonline.com/common/v2.0", "same redirect url as the authorize call", correct client credentials, null, null);
In the portal "App registration (preview)" I have it set to allow all kinds of Microsoft accounts, AD and outlook.com etc...
Since I'm using common as the authority for both calls I expected this to work, ideas why it doesn't?

I solved exactly the same issue on my code. In my JWT payload the aud was incorrect. That's pretty much what the error states.

Related

Why does CRM Online return 401 unauthorized in my scenario?

I am trying to implement server-to-server integration with Dynamics CRM Online 2016 and BizTalk 2013 R2. I am using the WebHttpBinding to call the CRM web API, which requires a bearer token supplied as an http header:
Authorization: Bearer [base64string]
I have written a client message inspector which calls Azure AD using ADAL to acquire an access token. This is secured with a client assertion certificate, which is assigned to the registered app in our AD tenant:
var token = context.AcquireTokenAsync(this.ResourceUri, assertionCert).Result;
ResourceUri is https://[myorganisation].crm4.dynamics.com
assertionCert is a ClientAssertionCertificate created using the app registration application ID and an x509 certificate in the machine certificate store that is registered to the app as a KeyCredential
This 'works' in that it returns a token and I can decode this token to inspect the claims - there are a fair number of them, I have no way of telling whether this is the set of claims that CRM requires.
The AD app registration is configured with delegated permissions to the CRM instance.
I have set the application ID in the CRM local user to that of the app registration.
Upon calling the webAPI and supplying this token, CRM responds with 401 unauthorized.
I have repeated the same process in a powershell script and in PostMan, all of which appear to show the same behaviour.
What else am I supposed to do to make CRM accept my access token?
edit #1: Tried hardcoding the authority URI to https://login.windows.net/[my-tenant-id]/oauth2/token rather than what comes out of dynamically acquiring the authority through AuthenticationParameters - this is the same value except ending with /authorization instead of /token. This makes zero difference.
edit #2: An administrator I am working with pointed out to me that the application user I am expecting to use had no user roles assigned - this has been amended to have a role which should allow API access, but this also made no difference.
edit #3: Set oauth2AllowImplicitFlow to true in the manifest for the app registration. This doesn't make any difference.
edit #4: Made some progress by creating a new app registration, this time as a Native app rather than a web app. I managed to get a token using a client secret, and this was accepted - BUT when assigning a certificate to the app, and presenting a ClientAssertionCertificate as before, I get the response from the authority:
Error validating credentials. AADSTS50012: Client is public so a client_assertion' should not be presented.
WHY? What does 'Client is public' mean? Just work!
Hrrrmph!
Turns out that the original situation I had tried and failed with, now works.
Web application registration with delegated permissions to CRM Online
Install a client certificate on the client machine, and register this same certificate to the app using New-AzureADApplicationKeyCredential
Link the app registration to a CRM Application User created for this purpose (they are fundamentally different to interactive users) - n.b. this screen is not easy to find
Call AcquireTokenAsync() from ADAL
Just works
I am at a loss to explain why this didn't work the first time I tried it, as CRM doesn't supply any information as to why token validation failed.

Requesting additional scopes returing incorect authorization code

This question is regarding Authorization code and include_granted_scopes in Google OAuth2 for incrementally changing scope.
In my web application, I ask for basic profile info as the scope:
https://www.googleapis.com/auth/userinfo.email )
When a Gmail user signs up with us. After the user preforms some actions, I request additional scopes by setting "include_granted_scopes=true" in authorization url.
At this point, my authorization url looks like this:
https://accounts.google.com/o/oauth2/auth?client_id=3490600xyz00-xyz....apps.googleusercontent.com&login_hint=hello#example.com&redirect_uri=https://www.example.com/google-signup-callback&response_type=code&scope=https://mail.google.com https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/gmail.compose https://www.googleapis.com/auth/gmail.modify&access_type=offline&approval_prompt=force&state=da503933-8979-409b-988a-24a9542ad98a&redirect=label&include_granted_scopes=true
Now in the oauth callback I get the same "Authorization code" which I received when I did oauth earlier using basic profile scope. If I try to get the authorization token by calling "https://accounts.google.com/o/oauth2/token" with "grant_type" set to "authorization_code", it returns
"Code was already deemed".
Now how do I get the new "Auth token" and "Refresh token" which has the new scope? The old auth token does not have the new scope even if I refresh it using the old refresh token.
Prompt=consent is used to force the user to reauthenticate.

Where does Web API store generated tokens in order to validate subsequent requests?

I have a Web API and AngularJS client. The API is using default authorization provider given by visual studio to generate the token on token request with grant_type 'password'.
The AngularJS client is able to get the bearer token from Web API by calling the token endpoint with credentials and later passes this token to perform authorized requests in the API.
When AngularJS sends the token on any authorized API call, how is Web API able to validate the token? Where does the token get stored?
I checked in Identity tables in SQL server, I could not find any fields to store this token information. I checked in the configuration file, it is not stored there either. Could you please help me in understanding this concept?
Raj,
By default the token is not stored by the server. Only your client has it and is sending it through the authorization header to the server.
If you used the default template provided by Visual Studio, in the Startup ConfigureAuth method the following IAppBuilder extension is called: app.UseOAuthBearerTokens(OAuthOptions).
This extension coming from the Microsoft.AspNet.Identity.Owin package makes it easy for you to generate and consume tokens, but it is confusing as it is an all in one.
Behind the scene it's using two Owin middlewares:
OAuthAuthorizationServerMiddleware: authorize and deliver tokens
OAuthBearerAuthenticationMiddleware: occurs at the PipelineStage.Authenticate, read the authorization header, check if the token is valid and authenticate the user.
To answer you questions WebAPI is able to validate the token thanks to the OAuthBearerAuthenticationMiddleware, it will ensure that the token sent through the authorization header is valid and not expired. And the token is stored only by your client, if the client loose it, it will have to request a new one.
I advise you to get deeper in the OAuth protocol, and instead of using the extension UseOAuthBearerTokens, take a look at UseOAuthAuthorizationServer and UseOAuthBearerAuthentication, it will help you to better understand how it works.
The generated token will most likely be a JWT (Get Started with JSON Web Tokens), which means it's a self-contained token that is signed with a secret/key that only the server or other trusted parties know.
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed.
(emphasis is mine)
This means that when receiving the token the server can ensure that:
the token was originally issued by a trusted party by checking that the signature is valid.
the token is associated with a user that has permissions to perform the following request because the token itself contains information that uniquely identifier that user.
This type of approach has the side-benefit that the server does not need to keep track or store the generated tokens in order to validate them at a later time. Since no one else has the secret/key you can't modify the token without making the signature component invalid, which would then mean a faked token would end up being rejected by the server.
This is a simplified description of what happens, there are much more details around how to issue and validate tokens correctly. You should read the OAuth2 and OpenID Connect specification to learn more on the subject of token-based authentication.
Also note that I assumed a JWT token because it's the format that currently has the most widespread adoption to accomplish scenarios like these ones and it's also the token format to use in conjunction with OAuth2 and OpenID Connect. However, it's still possible to achieve the same with other token formats.

Error 403 "you are not authorized to access this API " Email setting API

I am writing a code in salesforce to update Email signature using the API documentation mentioned in https://developers.google.com/admin-sdk/email-settings/. I am using a 3 legged approach.
Considering that this is an API for domain admins, My questions is
can a user ( non - admin) provide authorization for this API ?.
And can the access token returned as a result of this authorization be used to update his email signature. ?
Right now I am getting an Error 403- "you are not authorized to access this API
Note that this is working fine if a domain admin provide authorization and his access token is used to update his/ any user's email signature
Thanks for your help
With the new updates on the GMAIL Api you can get the user signature by using the method "Users.settings.sendAs: get" explained here https://developers.google.com/gmail/api/v1/reference/users/settings/sendAs/get and it does not require the user to be an admin. This method returns a Users.settings.sendAs resource in the response body and this resource contains the property signature which you can manipulate.
Hope it helps!

WAAD Authentication with WebAPI OData service consumed by Excel PowerQuery

I've created a WebAPI OData 3.0 web service with an OWIN middleware, which is configured for authentication with Windows Azure Active Directory.
The ODataControllers are marked with an [Authorize] attribute, and the IAppBuilder is configured as follows:
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters {
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
},
});
ida:Tenant is my Windows Azure tenancy, and ida:Audience is the App ID Uri.
Now I would like to consume this service using Excel PowerQuery, authenticating using an account from the AzureAD. However, when I choose "Organizational account" and try to "Sign in", I get the following error:
Unable to connect. This credential type is not supported for this resource.
In Fiddler I can see that the request is made with a Bearer header, but it is empty.
I would like to achieve a behavior similar to when querying AzureAD Graph.
For example, if I try to consume https://graph.windows.net/.onmicrosoft.com/users?api-version=2013-04-05, a single sign-on window opens, and in Fiddler I can see that a token is passed.
How can I achieve this behavior? what am I missing?
Thanks!
Here is the expected flow between PowerQuery and an OData service during authentication:
When you enter the URI to your service in the builder, click ok, you will get a credential prompt asking for your credentials to access the service.
Typically, you would choose Organizational Account if Azure Active Directory (AAD) is your Identity Provider.
When you click sign in, PowerQuery will send a challenge request to your service, which is the empty bearer you are seeing. The reason is, we don't know what's your identity provider or where should we log you in, the request is expecting a 401/403 response with a WWW-Authenticate header that has the authentication endpoint url.
Here is the expected header format:WWW-Authenticate authorization_uri=”token service uri” quotes are optional. If we don't find that header, you get the error message 'Unable to connect. This credential type is not supported'.
For example, in your scenario, the token service uri is https://login.windows.net
When we receive that response, we will get the url from the header and issue a login request, at which point you will see the login page from AAD and you will be able to login using your organizational credentials.
We will wait for the sign in result, which should be a token, that token will be used to fill in the bearer in the header at anytime you request data from that service.
There are two important things regarding your application object in AAD to make this work:
The AppIdUris property has to have a wildcard URI that would match with your service URI. When we send the login request we have to include a resource id, the resource is the authority of the service we are connecting to. So if your service url is: myservice.com/myODatafeed.svc, the authority includes the scheme, the host and the port number, myservice.com/ would be the authority. For services that might have different tenants for example: company1.myservice.com, the AppIdUri has to have https://*.myservice.com. Otherwise, just https://myservice.com.
The second thing (and this on is AAD specific), AAD doesn't support first party client (PowerQuery) to third party service (your service) authentication today. but hopefully soon enough :) Maybe just when you get the rest done :)!
Update: This has been enabled in the latest release of PowerQuery. Your app will need to expose the user_imperonation scope, and you are good to go :)!

Resources