Generate Bearer Token using Microsoft Graph - c#

I have Web API built in .net framework 4.6. I secure my API using Azure AD. For the purpose of development, I need to generate token so I can use it for testing and debugging. How can I generate token from Microsoft Graph that I can use to authenticate to my API?
I tried this https://login.microsoftonline.com/{tenantId}/oauth2/token endpoint but the token it generates is not valid. I get 401 using the token from that endpoint.
enter image description here

The error "401 unauthorized" usually occurs when you missed giving resource parameter while generating access token.
If that's the case, you will still get the access token but when you are using the token to authenticate to your API, you will get "Invalid token" error.
To resolve the error, please include below parameters while generating access token:
Make sure to include resource parameter and other required parameters like below:
I tried in my environment, after including the above parameters, I got the access token successfully like below:
If the above solution does not work, try with different grant_type parameter.
For more information, please refer below links:
401 Unauthorized Error–Azure Active Directory (AD) – Microsoft Azure Articles.. (wordpress.com).
Getting Access Token for Microsoft Graph Using OAuth REST API - DZone Security
Azure registered app error: The user or administrator has not consented to use the application with ID - Stack Overflow

Related

Possible to get access token on behalf on user without MS Library in Razor?

I am writing a Razor page application that get's the users data in Azure AD in the form of a HTTP GET call.
However, most of the documentation I found says to use the MS GRAPH library- is there a way to get the access token on behalf of the user with just standard HTTP?
I am not sure how to get the prompt to log into Office365 to show up from my razor pages application.
You could get access token with auth code flow.
Get an authorization code in browser:
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id={client-id}
&response_type=code
&redirect_uri={redirect_uri in azure portal}
&response_mode=query
&scope=https://graph.microsoft.com/.default
&state=12345
Get access token with the previous code:
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
client_id={client-id}
&scope=https://graph.microsoft.com/.default
&code={code from previous step}
&redirect_uri={redirect_uri in azure portal}
&grant_type=authorization_code
You will obtain the upn(The username of the user) and others after decoding the access token. If you have the required permission of MS Graph, you could also get the details of user with the API.

How to solve this error The remote server returned an error: (401) Unauthorized using Dropbox developer API

I have configure dropbox developer API in c#. and pass token and secretkey in below method.
OAuthToken oauth = new OAuthToken(DropboxAccessToken,DropboxAccessSecretKey);
var api = new DropboxApi(ConsumerKey, ConsumerSecret, oauth);'''
var account = api.GetAccountInfo();
Last statement raise "The remote server returned an error: (401) Unauthorized" this error.
Please help me how to solve this and please let me know if any missing condition or steps.
Based on the code you shared, it looks like you're trying to use OAuth 1 with Dropbox API v1. (OAuth 1 uses separate access token key and secrets parts, whereas OAuth 2 uses a single bearer access token. Also, the GetAccountInfo method name indicates Dropbox API v1.)
Dropbox API v1, along with the use of OAuth 1 with it, are retired now. You should instead use Dropbox API v2 with OAuth 2. For .NET, we recommend using the official Dropbox API v2 .NET SDK. It includes instructions for getting started, full documentation, and example apps.

How to get OAuth2 access token for EWS managed API in service/daemon application

Scenario
I have an Exchange Online environment and service/daemin (no interactive user) application on the Azure VM. Service uses EWS managed API to work with emails in the mailbox of any tenant user. Now EWS client uses Basic authentication that, according to Microsoft, will become unsupported in EWS to access Exchange Online.
Question/Issue
So, I need to find a way to get valid access token for service/daemon application to use with EWS managed API.
My findings
The following article shows an example of using OAuth 2.0 with EWS managed API. This example works, but it uses interactive method of getting consent (sign-in form appears allowing user authenticate themselves and grant requested permission to application) that is not suitable for service/daemon app scenario, because there is no interactive user.
For service/daemon application I need to use client credential authentication flow.
Registered application
Using admin account on https://aad.portal.azure.com portal I registered application with Azure Active Directory. Added client secret for registered application.
Aforementioned article uses https://outlook.office.com/EWS.AccessAsUser.All as a scope. But I did not find permission with such a URL on the portal. I found only the following permissions under Office 365 Exchange Online > Application permissions > Mail:
https://outlook.office365.com/Mail.Read Allows the app to read mail in all mailboxes without a signed-in user
https://outlook.office365.com/Mail.ReadWrite Allows the app to create, read, update, and delete mail in all mailboxes without a signed-in user.
I added both of them and granted admin consent for all users.
Getting access token
For testing purposes and simplicity I did not use any auth libraries (ADAL, MSAL etc.). I used Postman to get access token, then set token variable in debug (see code snippet later in the post).
I tried different endpoints to get acess token.
OAuth 2.0 token endpoint (v2)
POST: https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token
grant_type=client_credentials
client_id=***
client_secret=***
scope=https://outlook.office.com/EWS.AccessAsUser.All
Sending this request produces the following error response:
AADSTS70011: The provided request must include a 'scope' input parameter. The provided value for the input parameter 'scope' is not valid. The scope https://outlook.office.com/EWS.AccessAsUser.All is not valid.
I tried changing scope to https://outlook.office.com/.default. Access token was returned, but it appeared to be invalid for EWS. EWS client throws 401 error with the following value of x-ms-diagnostics response header:
2000008;reason="The token contains no permissions, or permissions can not be understood.";error_category="invalid_grant"
OAuth 2.0 token endpoint (v1)
POST: https://login.microsoftonline.com/<TENANT_ID>/oauth2/token
grant_type=client_credentials
client_id=***
client_secret=***
resource=https://outlook.office.com
Access token was returned, but also appeared to be invalid for EWS. EWS client throws 401 error with the same value of x-ms-diagnostics response header as described ealier in #1.
Use aquired access token with EWS managed API
Here is code sample that I used to test EWS client with access token acquired in Postman:
var token = "...";
var client = new ExchangeService
{
Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx"),
Credentials = new OAuthCredentials(token),
ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress,
"user#domain.onmicrosoft.com"),
};
var folder = Folder.Bind(client, WellKnownFolderName.SentItems);
We had a similar problem: We wanted to use a Service Account to connect to a single mailbox and just doing some stuff with the EWS API (e.g. searching in the GAL) and the full_access_as_app seems like an overkill.
Fortunately it is possible:
Follow the normal "delegate" steps
And use this to get a token via username/password:
...
var cred = new NetworkCredential("UserName", "Password");
var authResult = await pca.AcquireTokenByUsernamePassword(new string[] { "https://outlook.office.com/EWS.AccessAsUser.All" }, cred.UserName, cred.SecurePassword).ExecuteAsync();
...
To make this work you need to enable the "Treat application as public client" under "Authentication" > "Advanced settings" because this uses the "Resource owner password credential flow". (This SO answer helped me alot!)
With that setup we could use a "tradional" username/password way, but using OAuth and the EWS API.
You can protect your client application with either a certificate or a secret. The two permissions that I needed to get this to work were Calendars.ReadWrite.All and full_access_as_app. I never tried acquiring my token via PostMan, but use AcquireTokenAsync in Microsoft.IdentityModel.Clients.ActiveDirectory. In that call, the resource parameter I use is https://outlook.office365.com/. It's pretty simple once you know all the little twists and turns. And full disclosure: I was one lost puppy until MSFT support helped me through this. The doc on the web is often outdated, conflicting, or at best, confusing.
You need to register your app in Azure and use certificate based authentication. https://blogs.msdn.microsoft.com/emeamsgdev/2018/09/11/authenticating-against-exchange-web-services-using-certificate-based-oauth2-tokens/
I run into the same issue while following Microsoft official docs for OAuth 2.0 client credentials flow
According to the Microsoft identity platform and the OAuth 2.0 client credentials flow, the scope "should be the resource identifier (application ID URI) of the resource you want, affixed with the .default suffix" (see default scope doc).
So the question is how to convert https://outlook.office.com/EWS.AccessAsUser.All into the resource identifier.
Experimentally I manage to make it working using scope=https://outlook.office365.com/.default. I granted full_access_as_app (Office 365 Exchange Online / Application permissions) and got administrator consent for it.
I did face this issue while implementing OAuth for EWS. My application is not using EWS Managed API. Here is what all I did to make it working.
Added permission Office 365 Exchange Online > full_access_as_app to application.
Acquired access token for scope https://outlook.office365.com/.default.
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
form-data = {
client_id,
client_secret,
grant_type: 'client_credentials',
scope: 'https://outlook.office365.com/.default',
};
Added access token as Authorization header and ExchangeImpersonation SOAP header to the request.
<SOAP-ENV:Header>
<t:ExchangeImpersonation>
<t:ConnectingSID>
<t:PrimarySmtpAddress>user#domain.com</t:PrimarySmtpAddress>
</t:ConnectingSID>
</t:ExchangeImpersonation>
</SOAP-ENV:Header>
Late answer, but since this seems to come up, and I was just working with this... why not.
If you use Microsoft's v2.0 URLs for OAUTH2 (https://login.microsoftonline.com/common/oauth2/v2.0/authorize and .../common/oauth2/v2.0/token) then the scope for Office 365 EWS is:
https://outlook.office365.com/EWS.AccessAsUser.All
You'll probably want to combine this scope with "openid" (to get the signed in user's identity) and "offline_access" (to get a refresh token). But then offline_access may not be necessary when using client credentials (because you don't have to prompt a human user for them every time you need an access token).
In other words:
params.add("client_id", "...")
...
params.add("scope", "openid offline_access https://outlook.office365.com/EWS.AccessAsUser.All")
If using v1 OAUTH2 URLs (https://login.microsoftonline.com/common/oauth2/authorize and .../common/oauth2/token) then you can use a "resource" instead of a "scope". The resource for Office 365 is https://outlook.office365.com/.
Or in other words:
params.add("resource", "https://outlook.office365.com/")
Note that in the latter case, you're not asking for any scopes (it's not possible to combine "resource" with scopes). But the token will automatically cover offline_access and openid scopes.
I used this method successfully:
Install Microsoft Authentication Library module ( MSAL.PS)
https://www.powershellgallery.com/packages/MSAL.PS/4.2.1.3
Configure Delegate Access as per MSFT instructions: https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth
Configure ApplicationImpersonation for a service account as normal
Grab your token
$cred = Get-Credential
$clientid = ""
$tenantid = ""
$tok = Get-MsalToken -ClientId $clientid -TenantId $tenantid -UserCredential $cred -Scopes "https://outlook.office.com/EWS.AccessAsUser.All"

How to obtain "B2C JWT Access Token" from the signed in User?

I'm working with a .Net Core Web API and a .Net Core Web MVC Application. They both use Azure AD B2C to authenticate users. But in order to get a response from a HttpRequest from the Web API I need to provide the JWT Access Token from B2C for the signed in user on my web MVC application. Is there a way to obtain this access token inside a controller using the authenticated "User".
I have tried accessing the claims of the signed in user but no luck there, I have also used jwt.ms to review that the B2C workflow works well and that the JWT token is being generated and it works as well. The MVC application is authenticating the user and the web API is working fine with a hardcoded token. I just need to obtain the access token from a signed in user rather than doing it hardcoded.
I expect to be able to get the B2C JWT access token so that I can later on pass it to the Web Api and be able to secure my requests.
After getting some help from the MS AzureADB2C.UI GitHub crew we were able to solve the issue. The issue was that the tokens aren't saved by default on the library, so we needed to configure OIDC to specify that the tokens have to be saved for future use within the application. And so here is the example code of the "Startup" configuration and the example of how to query the "JWT access token" from the controller.
Startup.cs:
services.Configure(AzureADB2CDefaults.OpenIdScheme, options => {
options.SaveTokens = true;
});
Controller:
string idToken = await HttpContext.GetTokenAsync("id_token");
More information on how was the issue solved can be found on the following link:
https://github.com/aspnet/AspNetCore/issues/11424
You can refer to this sample application.
It uses the ASP.NET Core Azure AD B2C middleware to authenticate the end user and MSAL.NET to acquire, cache, and refresh the access token.
The access token is acquired in the AzureADB2COpenIdConnectOptionsConfigurator class.
A code example for a controller method referencing the access token is here.
Is it the actual token string you need? If so, you can access the headers using the HttpContext within the controller? The HttpContext will have a collection of headers that were passed in

DocuSign Service integration authentication with jwt

I want to implement DocuSign Service integration authentication with jwt flow.
I’ve generated valid jwt (validated on jwt.io) and I can successfully obtain access token based on jwt according to https://docs.docusign.com/esign/guide/authentication/oa2_jwt.html#requesting-the-access-token
I found on this blog post: https://www.docusign.com/blog/dsdev-docusign-developers-look-inside-new-authentication-apis/ that sub claim should be omitted in case application represents user in the system (which I need):
sub: The user id of the principal you are requesting a token for. If omitted a token will be issued to represent the application itself instead of a user in the system. Required: No
But in next step "Obtaining the Base URI" that states:
The first thing you should do after getting your access token is to use the /oauth/userinfo endpoint to get user’s account and base URI information that you’ll use to access the DocuSign API.
GET /oauth/userinfo Authorization: Bearer eyJ0eX...AnHDQ0bbA
Fails with status code 401 Unauthorized with response body details:
{
"error": "internal_server_error",
"reference_id": "e051ca48-....f0f"
}
I also tried to call Login (from AuthenticationApi - DocuSign.NetCore 1.1.0 nuget package), with default authorization header containing an access token like this:
Configuration.Default.DefaultHeader.Add("Authorization", string.Format("Bearer {0}", accessToken));
AuthenticationApi authApi = new AuthenticationApi(Configuration.Default);
LoginInformation loginInfo = authApi.Login();
Code above works only if I use OAuth2 access token that I can obtain directly from api explorer:
https://apiexplorer.docusign.com/#/esign/restapi?categories=Authentication&tags=Authentication&operations=login&mode=basic
but when I use access token that I've obtained by following official documentation (described above) I get exception:
DocuSign.eSign.Client.ApiException: ‘Error calling Login: {
“errorCode”: “USER_AUTHENTICATION_FAILED”,
“message”: “One or both of Username and Password are invalid. Invalid access token”.
What seems to be that I'm missing?
As Amit says, you need to provide a userID (guid format). The fact that you're receiving the Consent Required is good news: you're almost there.
Your user can grant consent individually or you can grant blanket consent at the org level if you have org admin turned on.
See my video or blog post for how to individually grant consent.
Ommitting sub is not yet implemented, it is a future state which is yet to be implemented. As of now, you always need to pass sub in the call, and you can get Accesstoken for a user only. That's a blog link with the big picture overview of what's coming with new OAUTH, but whats currently implemented is available at DS Docs

Categories

Resources