Authenticate Office 365 API and Send Email from ASP.NET MVC app - asp.net-mvc

I have an ASP.NET MVC web application that wants to send email messages to different users. The goal is to have a re-usable API in my MVC app that can send single/bulk emails from different views.
My idea is to create a custom Web API that my MVC application can call to send emails using Office 365 API. Now assume that we have 2 projects:
MVC Web App -> This contains a page with UI fields like To, From, Body, Send Button etc.
MVC Web API -> This contains references to Office 365 library and endpoints to send emails
Will this scenario work to send emails as I do not want the users to be redirected to their individual sign in page and enter their office 365 credentials. I was wondering if I could call some office 365 API endpoint and pass them an email address like xyz#office365.com and it would send me an auth token which I could use to send the emails.
Correct me if I am wrong or anyone has a better idea?
-------UPDATE ON 17th May 2017 -------
Sorry Nan Yu for replying late. I was a bit occupied with other priorities so did not get a chance to look into more details on your code samples. I appreciate your suggestions but at this point I have other priorities to work on. I don't know how will I be able to authenticate against the AD as we have a different sort of architecture. Imagine we have 5 companies who use our web application. All 5 companies have their own Office 365 accounts and AD. We use our SQL database to authenticate them before giving access to our web application like most web applications will do but we cannot authenticate them against their AD as they are not part of our AD network.

If you want user to authentication in Azure AD in MVC app(user login with their credentials) , then in mvc app calls a web API and then the web API calls O365 rest apis after obtaining a token to act On Behalf Of the original user. You could use the OAuth 2.0 On-Behalf-Of flow . For more information about how the protocols work , you could refer to this document and this code sample .
If you want to call Office 365 library in web api using its app identity (instead of a user's identity) to get access token , without any human interaction such as an interactive sign-on dialog , you could try OAuth 2.0 client credentials . Please refer to this document and you could related code samples in here(Server or Daemon Application to Web API section).
Update :
You could 1) use asp.net identity and enable azure ad External login , then in web api you could send mail On Behalf Of the original user by using OAuth 2.0 On-Behalf-Of flow .
2) Acquire token With client credentials flow in web api :
POST https://login.microsoftonline.com/<tenant>/oauth2/token
Content-Type: application/x-www-form-urlencoded
client_id=<clientid>&resource=https://graph.microsoft.com/&client_secret=
<client secret>&grant_type=client_credentials
Then using the access token(app identity) you could send mail by :
POST https://graph.microsoft.com/v1.0/users/<userPrincipalName>/sendMail
Content-type: application/json
Authorization : Bearer token
{
"message": {
"subject": "Meet for lunch?",
"body": {
"contentType": "Text",
"content": "The new cafeteria is open."
},
"toRecipients": [
{
"emailAddress": {
"address": "ny#chencl.onmicrosoft.com"
}
}
],
},
"saveToSentItems": "true"
}
You could pass userPrincipalName from MVC . And you should grant Send mail as any user application permission of microsoft graph for you web api in azure portal.

Related

SPA + Backend + Office365 SSO

I am building an application consisting of the following
SPA (Provides a front end for the user to perform actions) - app.myservice.com - React JS
API (Provides the core business logic and is called by the SPA) - api.myservice.com - Node JS
What I would like to do is allow people to "Signup" to my application (as a whole) using Office 365.
However.... I want the API to generate JWT tokens which the SPA will use to communicate with the API in the future. I do not want the SPA to have Office365 specific tokens.
The process would look like this at a high level:
User goes to app.myservice.com
User clicks "Signup"
User is redirected to Office365 to provide login details
Office365 redirects to my API
API creates a local user in its database
API generates a JWT
API returns JWT to SPA
SPA calls API using JWT to perform actions.
What is unclear to me, is what OAuth2/OpenID flow type to use in order to achieve this.
Further this, I would like to understand if my approach has any flaws in general.
Many Thanks
In step 3 above, I think your SPA should redirect to Azure AD, which is where the user signs in. Your SPA will then receive an Azure AD token and can send it to the API. The API can potentially read user info and create a user if required. APIs should not issue their own tokens or receive redirects. Not sure if this will 100% meet your requirements but it is the standard pattern for the 3 legged SPA and API OAuth 2.0 based dance.

Is there any to get user unique identity after authentication process of MS Graph API?

Currently, I am using the Microsoft OneNote API (REST) to read the content of OneNote Pages. I have already subscribed for the notifications on the event of any changes happens in any page's content. Microsoft so sends me a notification for every change in the content of any page. They send a combination ofX-Authenticated user_id and subscription ID in the webhook. Like this:
{
"value": [
{
"subscriptionId": "WLID-00000000441A2E0C",
"userId": "WLID-1F50AB22CBE04E58"
}
]
}
Recently, MS released the Graph API and recommended to use this one instead of the OneNote API. SO, I am migrating my implementation from OneNote API to Graph API.
I was getting userId (WLID-1F50AB22CBE04E58) with X-Authenticated-userId in the headers of the response of one of this API in OneNote API
https://www.onenote.com/api/v1.0/me/notes/notebooks
But, I am not getting this with Microsoft Graph. There should be a unique identity for each user who is completing the Authentication process.
Where will I get userId from Microsoft Graph?
Authentication isn't handled by Microsoft Graph, it's handled by Azure Active Directory. You can get additional user information using OpenID Connect by requesting the scopes openid, email, and profile.
You can also get the current user's profile by calling the /me endpoint (https://graph.microsoft.com/v1.0/me).
Webhook Subscriptions also return a creatorId which will be the id for the authenticated user that created the subscription.

(How) does one secure a Web API with OpenID Connect (or not?)

Is it recommended or good practice to protect a Web API directly with Open ID Connect or not?
The setup:
Mobile App
Authorization Server (ADFS 4.0)
Web API (ASP.NET Core)
Currently I do the normal OAuth2 "Authorization Code Flow", and then pass the access_code to my Web API in the HTTP Header as "Authorization: Bearer ".
In ASP.NET core I just do the usual
services.AddAuthentication(...).AddJwtBearer(...)
Works fine.
But everyone talks about OAuth2 beeing only "pseudo-authentication" with certain flaws. I want my Users to be a properly authenticated before using my Web API. So it seems like Open ID Connect should be the way to go, aka "real authentication".
But does it actually work to "consume" Open ID Connect authentication in an ASP.NET Core Web API? And if yes, how? And is it good practice? All samples seem to be about Web Sites, not Web APIs.
There is an extension method
services.AddAuthentication(...).AddOpenIdConnect()
But here Implement OpenID connect Authetication in asp.net WEB API they state that "this component is designed for user interactive clients".
What i also don't understand, what would I do with the "id_token" I get from Open ID connect.
Currently i just pass the "access_token" as Bearer.
How do i consume the id_token?
Some clarifications:
The API does not act on behalf of a user (access to company data).
The API already has access to the "data". It does not require any auth workflows for itself nor does it need to pass the users credentials along.
The API needs to know "WHO" the user is, and it has to be done in an modern and good way
That's why I was thinking of OICD with its "real auth" (VS Oauth2-only which is "pseudo").
I basically cannot wrap my head around how the stuff returned from OICD (id_token) will be passed to my Web API.
OIDC is an OAuth workflow. It merely extends OAuth; it is not a replacement for it. APIs are typically authorized either by token or client secret. The difference is simply whether it's acting on behalf of a specific user or not. For example, something like the Facebook API has both workflows for its API, you generally operate with Facebook's API as a client app using the app id and client secret for your app, or you can do user-specific things like create a post on the user's wall given an authorization token.
That authorization token almost invariably comes from an OAuth workflow. Given your stated setup, your mobile app would handle this to get an auth token for the user from your ADFS server. Your API, meanwhile, would actually probably do both. It would communicate both using an assigned client secret and a user auth token, if the mobile app provides it with one.

Authorization Oauth2 bad request for PowerBI user

I am building a sample ASP.NET 5 (vNext) web application to act on behalf PowerBI users through Power BI API.
I followed all the steps here to register my application and I have the ClientId.
The app was added to my Azure Active Directory realavaloro.onmicrosoft.com
My web application is able to redirect the user to the authority https://login.windows.net/common/oauth2/authorize/passing as query parameters the response_type, clientId, resource and redirect_uri
"response_type": "code"
"resourceUri": "https://analysis.windows.net/powerbi/api",
"clientId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"redirectUri": "http://localhost:59136/"
The browser is properly redirected to the microsoft page and the user enters his Power BI credentials. If authenticated, it is redirected to the redirect_uri with the code + session_state
The problem is that I don't fully understand this mechanism.. :)
If I use my PowerBI test account credentials (diego#realavaloro.onmicrosoft.com) the authentication is successful and the browser is redirected properly with code + session_state
But if I try to authenticate with other PowerBI credentials, for example joe#companyb.com it fails to authenticate with the Bad Request message:
AADSTS70001: Application with identifier 408c866f-ad71-4354-b9fd-c954cae84dd7 was not found in the directory companyb.com
I thought any user with an account in PowerBI would be able to, through our web application, user his PowerBI account through the API provided our web application has permission.
But it seems that if we want that to happen with this approach every user would need their own Azure Active Directory to authenticate against.
Is there anything I am missing here?
Is there any option to allow our application act on behalf ANY Power BI user?
Thank you!
PS: I built my test web application following guidelines at https://github.com/PowerBI/getting-started-web-app-asp.net
I will answer myself. The reason I my web application couldn't authenticate external users with their Power BI credentials was (duh!) because I had not configured my web application in Azure AD as multi-tenant.
Thanks to this great presentation https://channel9.msdn.com/Events/Ignite/2015/BRK3551 I found some good answers including the meaning of multi-tenant :)
I still have to investigate the Azure libraries to manage all these Authentication headers for me and get my head around OAuth2 but at least I can say now that the authentication works for external users.

office365/azure oauth using delegated user id

My goal is to write some code to enable an Office 365 user to access files in OneDrive for business via REST API. I have registered an application in Azure AD (Web App/single tenant) and have a redirect URI to receive the OAuth token. I want to use the "delegated user identity with OAuth" scenario. To see how it works, I use the "Office 365 OAuth Sandbox" here: https://oauthplay.azurewebsites.net/. When I "Authorize using own account" and enter any valid Office 365 user credentials, I get an access token back. When I replace the client ID and redirect URI in the authorization URL with the info of my registered app, I can only get the token when I enter a user registered in my app (otherwise I get an error 50012 during sign-in). What do I have to change in my configuration to allow any Office 365 user to get an authorization token (like the Sandbox does) ?
You need to mark your web application as multitenant, or Azure AD will constrain all callers to be from the tenant in which you provisioned the application.
Take a look at https://github.com/AzureADSamples/WebApp-WebAPI-MultiTenant-OpenIdConnect-DotNet for an example of a web app that is multitenant and invokes a Microsoft API. Note that you don't necessarily need to validate issues as shown in the sample, just do what makes sense for your scenario (which might mean even not validating).

Resources