Office365 API: OAuth2 AccessTokens for app-only require that the - c#

I'm creating a subscription request to Outlook Push Notification using this URL :
https://outlook.office365.com/api/v2.0/me/subscriptions
I have used certificate based authentication with Azure AD to acquire token using the following code:
AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/mytenant/oauth2/v2.0/token");
AuthenticationResult authResult = await authContext.AcquireTokenAsync("https://outlook.office365.com/", certificate);
When calling the subscription API I'm getting a Forbidden error with the following response:
x-ms-diagnostics: 2000008;reason="OAuth2 AccessTokens for app-only require that the target mailbox is explicitly specified with the api call";error_category="invalid_grant"
Could you please help me with where I'm going wrong or how to debug / solve this error.
Thanks in advance

Since you are using App-only tokens you are required by the API to explicitly specify the target mailbox in the URI.
Eg: https://outlook.office365.com/api/v2.0/Users(foo#bar.com)/subscriptions
me is only useful in case the target mailbox is same as authenticated user. However in case of app-only there is no authenticated user, do you have to be explicit.

Related

use of b2clogin.com when acquiring token with Client Credential Grant Flow

According to this official Microsoft document (and the documents referenced there) URIs using login.microsoftonline.com/myTenant/.. must be replaced by myTenant.b2clogin.com/mytenantId/..
For the interactive login with MSAL to get an ID token this works fine for me. But I can not figure out which URI to use with IConfidentialClientApplication and using a secret. I'm using MSAL 4.18 in a C# Windows application.
The following code works fine using login.microsoftonline.com.
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder
.Create(clientId)
// how must this URL look like when using b2clogin.com
.WithAuthority("https://login.microsoftonline.com/*MyTenant*.onmicrosoft.com/v2.0")
.WithClientSecret(secret)
.Build();
AuthenticationResult authenticationResult = await app
.AcquireTokenForClient(scopeArray)
.ExecuteAsync();
Whatever b2clogin.com URI I use (e.g. https://*myTenant*.b2clogin.com/*myTenantId*/v2.0) I get back an AADSTS50049: Unknown or invalid instance. response.
What am I missing? Can I continue to use login.microsoftonline.com for this case?
(This answer comes with a bit of twists, so please read till end :))
You should not generally continue to use login.microsoftonline.com for B2C, it will be retired on December 4, 2020.
Authority should be in format https://{your-tenant-name}.b2clogin.com/tfp/{your-tenant-ID}/{policyname} or https://{your-tenant-name}.b2clogin.com/tfp/{your-tenant-name}.onmicrosoft.com/{policyname}
Also, you should be using .WithB2CAuthority, not .WithAuthority for B2C in code for client setup (but there is a catch here for your case since it's Client Credential Grant which is in the later part of the answer).
Example code (though the example uses public client, in your case it's confidential client, just referring it for authority reference).
For details, refer this.
But since you are using Client Credential Grant Flow using client id and secret, it's not directly supported in B2C as documented here.
Although the OAuth 2.0 client credentials grant flow is not currently
directly supported by the Azure AD B2C authentication service, you can
set up client credential flow using Azure AD and the Microsoft
identity platform /token endpoint for an application in your Azure AD
B2C tenant. An Azure AD B2C tenant shares some functionality with
Azure AD enterprise tenants.
In summary, you can not use B2C directly for Client Credential Grant and workaround requires to use regular common enterprise AAD backend of B2C. So b2clogin.com part would not be applicable for this workaround. That mean only for this particular Client Credential Flow case, you should be continuing with login.microsoftonline.com since you are not actually using B2C in true sense for this.

Azure Active Directory B2C log in user with specified email address

I am using the following code to sign in the user at first time with AAD B2C using Microsoft IDP.
var localAccounts = (List<IAccount>) await AADB2C.PublicClientApp.GetAccountsAsync();
var authResult = await AADB2C.PublicClientApp.AcquireTokenInteractive(AADB2C.ApiScopes)
//.WithAccount(GetAccountByPolicy(localAccounts, AADB2C.PolicySignUpSignIn))
//.WithPrompt(Prompt.SelectAccount)
.WithLoginHint(WindowsUser.Email)
//.WithExtraQueryParameters("login_hint=" + WindowsUser.Email)
.ExecuteAsync();
I try to achieve to specify the login email address, so when the user log in the email address should be filled out at least. (Or make it readonly would be even better). For this I use the .WithLoginHint extension but it doesn't work.
Do you have any suggestion how can I solve it?
AAD B2C will be sent the login_hint param in the authorization request based off your code. Use a network trace in Chrome browser to confirm. Since there is only one IDP configured, AAD B2C redirects the user to Microsoft Account login.
AAD B2C will not pass through the login_hint parameter to the federated IdP when using the Built In user Flows, hence your observation of it "not working".
If you build this using Custom Policies, following this and this and add the following to your MS Account OIDC ClaimsProvider, B2C will pass through the login_hint using a claims resolver.
<InputClaim ClaimTypeReferenceId="prompt" DefaultValue="{OIDC:LoginHint}" />
You also need to define the claim prompt as follows:
<ClaimType Id="prompt">
<DisplayName>oidc prompt param</DisplayName>
<DataType>string</DataType>
<UserHelpText/>
</ClaimType>

Web API on-behalf-of adal id_token error

I have created a Web API in Azure.
This Web API makes some calls in SharePoint Online. Some of the api calls are on-behalf-of.
This Web API works fine until 01.05.2018 - and it works fine on old app services, which were created before 01.05.2018.
A microsoft staff member said:
As part of our security hardening efforts we do not allow id_token
redemption for any application created after 2018-05-01 00:00:00.
During the log in process of adal, I got the id_token. The id_token has got the same value as the access_token:
When I call the web api, I will send this token as bearer token.
The Web API takes this token (string accessToken) and starts the method 'AcquireTokenAsync':
var clientID = ConfigurationManager.AppSettings["ClientID"];
var clientSecret = ConfigurationManager.AppSettings["ClientSecret"];
var tenant = ConfigurationManager.AppSettings["Tenant"];
var appCred = new ClientCredential(clientID, clientSecret);
var authContext = new AuthenticationContext(
"https://login.microsoftonline.com/" + tenant);
var resource = new Uri(sharePointUrl).GetLeftPart(UriPartial.Authority);
var authResult = await authContext.AcquireTokenAsync(resource, appCred,
new UserAssertion(accessToken));
return authResult.AccessToken;
But in the line which calls 'AcquireTokenAsync' I have got the error message:
AADSTS240002: Input id_token cannot be used as 'urn:ietf:params:oauth:grant-type:jwt-bearer' grant
But where is the problem?
The problem is that you use the same application identity in the front-end and back-end, and MS does not allow you to use the Id token (which you use as an access token here because of the former) to get another access token.
A possible solution:
Register another application (the front-end JS app should be a Native app)
It should acquire an access token for your back-end API using either the API's client id or app Id URI as the resource
Then the API can exchange the access token for another access token
If this is a multi-tenant app, the migration is probably not going to be easy.
If it's single-tenant, then all should be possible.
Your front-end app should of course require permission to call your back-end API in Azure AD, and that permission should be granted.
Another solution would be to acquire the other access token in the front-end using ADAL.JS instead of using on-behalf-of in the back-end and attaching that to all API requests in addition to the Id token.

Outlook REST API: trying to call API using AZURE AD authentication

Using the office 365 Outlook REST API (version 2), I have a web application managing outlook subscriptions to specific mail boxes. I've been able to use the examples to obtain a token and call the API using the authorization code flow, successfully.
But now, I want to use a client credential flow and get a token using Azure AD authentication via delegate permissions (I gave the application all possible delegate permissions under office 365 exchange online). Similar to what I've seen here: Get Office 365 API access token without user interaction
I've registered my application and gotten my tenant ID, client ID & secret. I've been able to get a token but when I try to use it, I get 401, unauthorized back.
Here's how I'm getting the token:
AuthenticationContext authContext = new AuthenticationContext($"{authority}{tenantId}");
clientCredential = new ClientCredential(client_Id, secret);
authResult = await authContext.AcquireTokenAsync(resource, clientCredential);
authResult.AccessToken;
And here's how I'm trying to use the API (trying to delete the subscription using REST sharp in this code):
var token = await GetOtherToken(account);
rc = new RestClient("https://outlook.office.com/api/v2.0");
rc.AddDefaultHeader("Authorization", $"Bearer {token}");
request = new RestRequest($"me/subscriptions('{restSubId}')", Method.DELETE);
request.AddHeader("Content-Length", "0");
request.AddHeader("Content-Type", "multipart/form-data");
Looks like this is not possible. Please, someone, drop some knowledge. Thanks for reading.
When using client credential flow to acquire a token for resource , you are using application identity instead of as a user's identity. So you should assign application permission for your app(not delegate permissions) . In addition , since you are using app identity instead of user's identity , api can't recognize me(https://outlook.office.com/api/v2.0/me) . Please click here for how to build service and daemon apps in Office 365 .

Office 365 APIs Microsoft Graph authentication failed

I registered sample app from Microsoft graph sample app
And standard login is working but when I try to make it simplier by using this code:
var authContext = new AuthenticationContext(Settings.AzureADAuthority);
var token = authContext.AcquireToken(Settings.O365UnifiedAPIResource, new ClientCredential(Settings.ClientId, Settings.ClientSecret)).AccessToken;
I get the following error: Application with identifier '[ClientId here]' was not found in the directory microsoft.com
Setting.O365UnifiedAPIResource = #"https://graph.microsoft.com/";
Settings.AzureADAuthority = #"https://login.microsoftonline.com/common";
Does anyone know what can be the problem?
Settings.AzureADAuthority = #"https://login.microsoftonline.com/{tenant_id or tenant_name}";
When acquiring the token by using the client credential (client id + client secret). You should specify the tenant explicitly.
For example:
https://login.microsoftonline.com/{tenant_id}
or
https://login.microsoftonline.com/{your_domain.onmicrosoft.com}
BTW, as this registration will be for the sample app, it will only have the Mail.Send permission which is delegated permission. To acquire the app token, you also need to grant the app level permission in Azure AD since your are acquiring the app token rather than the user token.

Categories