I created a message extension for an App within Microsoft Teams that when clicked sends the message from Teams to my web service.
(one of these https://learn.microsoft.com/en-us/microsoftteams/platform/messaging-extensions/how-to/action-commands/define-action-command)
I don't need to authenticate the user, but I want to authenticate that the incoming request came from Microsoft instead of someone maliciously sending me data.
The Authentication method described by Microsoft here; authenticates the user individually on the system. Which I don't want as the user might not have an account.
There is a Bearer token in the header of the action's incoming request to my web service. Can I somehow utilize this to validate it?
You shouldn't validate the Bearer token sent from MS Teams to your MS Teams App.
The right way to do it is use the "client credentials grant" between your MS Teams app and your web service. The grant is described here: https://www.rfc-editor.org/rfc/rfc6749#section-4.4
Your MS Teams App will be the client. Each request your client sends to your web service will contain a token issued by either your web service or an external identity provider your web service trusts. This token will be validated by your web service to ensure the request is genuine.
This grant is suitable for service-to-service communication you described.
Related
I feel like I may be going a little mad here.
I have basic architecture that features a frontend react app (SPA Auth) which communicates with a backend GraphQL Nodejs API service (Protected Web API Auth), hosted in Azure and authenticating with Azure AD.
Frontend access token requires User.Read access to azure graph, and access to Backend exposed scope
Backend exposes an API and single scope for access
Backend also requires User.Read access to azure graph on behalf of the user
I have been trying to configure the authentication to use the On-Behalf-Of Flow.
The react app successfully retrieves an access token using it's own app registration details
The access token is supplied to the backend service with each GraphQL request
The backend service verifies the access token provided to it
The backend service requests it's own access token via the On-Behalf-Of grant_type urn:ietf:params:oauth:grant-type:jwt-bearer
This all works EXCEPT I cannot get past this issue -
The user or administrator has not consented to use the application with ID '9b56c153-be42-499a-a41a-20176ed2ce69' named 'service-cbcity-api'. Send an interactive authorization request for this user and resource.
Basically I have not been able to successfully configure the app registrations and token requests to ensure that when the backend requests it's token it is allowed to call User.Read on behalf of the originally authenticated user.
In the On-Behalf-Of documentation it states the following regarding using /.default scope -
/.default and combined consent
The middle tier application adds the client to the known client applications list in its manifest, and then the client can trigger a combined consent flow for both itself and the middle tier application. On the Microsoft identity platform endpoint, this is done using the /.default scope. When triggering a consent screen using known client applications and /.default, the consent screen will show permissions for both the client to the middle tier API, and also request whatever permissions are required by the middle-tier API. The user provides consent for both applications, and then the OBO flow works.
I have tried all sorts of combinations of configuration in the App Registrations as well as different combinations of scope requests and I simply cannot get this to function as expected; the prompt doesn't seem to include the combined consent.
The only way I have gotten it to function is by manually providing admin consent to the Backend app for User.Read, this just seems like a hack and I would prefer to correctly configure this to ask for users consent.
If anyone has configured something similar before (seems like an expected use case) please let me know how you got it working, including configuration like
App registration config for Frontend service (eg api permissions set)
App registration config for Backend service (eg exposed scope, api permissions, authorized client applications)
Scopes requested on various auth requests
At this stage I am going to have to revert to possibly using the one App Registration and sharing the same access token between frontend and backend, even though personally this seems like a poorer solution to me.
Figured it out, my main issue was that I confused known client applications list with Authorized client applications.
The Authorized client applications is present in the UI and is configurable from the Expose an API area -
However this is different from known client applications which is a setting only found if you edit the manifest -
The key pieces to this puzzle are -
Add your frontend app client id to the knownClientApplications in your backend app registration manifest
When doing login with the frontend app your scope needs to be {{api_clientid}}/.default, where {{api_clientid}} is your the client id of your backend app registration
This will present the API Permissions you have configured in the backend app registration to the user at time of consent, and it will permit your backend process to retrieve an AccessToken using the OBO flow.
For what it's worth, this is the tutorial that helped me realise I needed to update the manifest and gave me guidance on the exact OAUTH request format -
https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore-v2/tree/master/2.%20Web%20API%20now%20calls%20Microsoft%20Graph#how-to-deploy-this-sample-to-azure
I have 3 applications, one is desktop application and this is my client, second is my Web Api to secure and the last one is api which checks if the user with password exists.
In my case I want to connect this flow with Azure AD.
I think this should work like this:
1.DesktopApplication sending request with clientid,clientsecret, username and password to AZURE
2.Azure sending request with username and password to my api where I can check this user exist if exist I will return "true"(or somthing like this)
3. If api return "true" Azure can return to DesktopApplication token
4. DoesktopApplication will send request ot secure Web Api with token
5.DesktopApplication recive content from secure Web Api
Api in 3 point is not same api in 5 point.
Is it posible to do this flow with Azure AD or not? And if not can I do something with my flow something to secure Web Api by Azure and still store users in my old db(oracle)?
It would be better to use OpenID Connect authentication flows to authenticate the user and acquire a token that way.
The approach you are suggesting has a few downsides:
You are storing a client secret in a desktop application, which can be easily extracted by anyone.
The authentication flow that allows you to do this will not work with users who have MFA enabled / are federated users (on-prem AD/MS account/Guest account) / have expired password.
It trains users to be phished as they really should only enter their password to the actual login page.
So it would be better to use a flow like this:
Your desktop application uses Azure AD Authentication Library (ADAL) or Microsoft Authentication Library (MSAL) to authenticate the user, requesting an access token for your API
Desktop app calls API, API validates token signature, issuer, validity time etc.
It will show the user a pop-up window where they can login, and as a result you'll get an Id token (which tells your desktop app who the user is) and an access token for the API.
I have an azure b2c application. When I create a user through the Users application in portal.azure.com (or making a post request with postman) I have to send the client_secret of my b2c app to refresh a token.
But with users created through Powershell with the azureAD module I have an error saying that I shouldn't send the client_secret.
{
"error": "invalid_request",
"error_description": "AADB2C90084: Public clients should not send a client_secret when redeeming a publicly acquired grant.\r\nCorrelation ID: 39abec35-770c-42e6-bd65-438d6501a124\r\nTimestamp: 2018-04-09 14:43:13Z\r\n"
}
Why is that difference? How can I do to create a user that not requires the client_secret using the graph api?
Thanks in advance!
Germán
According to the error message, I assume that the App that you're using is a Native app (as juunas said, Powershell is also a native app), which also called public client in Oauth. client_secret is only required when your application is Web App/API,which also called confidential client in Oauth.
Refreshing the access tokens with Native App:
// Line breaks for legibility only
POST /{tenant}/oauth2/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq...
&grant_type=refresh_token
&resource=https%3A%2F%2Fservice.contoso.com%2F
NOTE: The application secret that you created in the app registration
portal for your app. It cannot be used in a native app (public
client), because client_secrets cannot be reliably stored on devices.
It is required for web apps and web APIs (all confidential clients),
which have the ability to store the client_secret securely on the
server side.
So, you can just delete the client_secretin the request body to resolve that.
Additional, Azure AD B2C doesn't support client_credentials flow. See details about this here.
I have created app service for mobile app. Then i have added Authentication to the app service. Then Selected Authentication type as "Log on with Azure AD". It is working fine.
Is it possible to have custom login page instead of browser based login screen?
I was able to get the token by using https://login.microsoftonline.com//oauth2/token. But not able to authorize the app service with this bearer token.
Is it possible to have custom login page instead of browser based
login screen?
This page is the authentication endpoint of AzureAD. Though it can be configured by Company branding, I think it cannot be customlized by yourself for Moblie APP.
I was able to get the token by using
https://login.microsoftonline.com//oauth2/token. But not able to
authorize the app service with this bearer token.
Authencation/Authorization for Web App is a feature that securing Web App behind those IDPs, NOT just like other azure resources you can use REST API to access it. I understand what you want to do . But this action is not recommended or supported.
I was able to get the token by using https://login.microsoftonline.com//oauth2/token. But not able to authorize the app service with this bearer token.
As juunas answered, your token may does not match the AAD provider you configured on Azure Portal. Details you could follow here to check your configuration. Moreover, you could use https://jwt.io/ to decode your access_token and validate the related properties (e.g. the aud should be the clientId you configured on Azure Portal,etc.).
As App Service Authentication / Authorization (EasyAuth) states as follows:
Users who interact with your application through a web browser will have a cookie set so that they can remain authenticated as they browse your application. For other client types, such as mobile, a JSON web token (JWT), which should be presented in the X-ZUMO-AUTH header, will be issued to the client. The Mobile Apps client SDKs will handle this for you. Alternatively, an Azure Active Directory identity token or access token may be directly included in the Authorization header as a bearer token.
For Azure Web App or Azure Mobile App, you could just access your endpoint as follows:
https://{your-app-name}.azurewebsites.net/api/values
Header: Authorization:Bearer {the id_token or access_token of AAD}
Or
https://{your-app-name}.azurewebsites.net/api/values
Header: x-zumo-auth:{authenticationToken}
Moreover, if you retrieve the access_token in your mobile app, you could also use it to retrieve the authenticationToken and use the authenticationToken for communicating with the backend endpoint.
POST https://{your-app-name}.azurewebsites.net/.auth/login/{provider-name,for your scenario, it would be AAD}
Body: {"access_token":"<your-access-token>"}
For your mobile client, you could use the client for Azure Mobile Apps, details you could follow here. Also, you could follow Authenticate users to understand the client-flow and server-flow authentication for App Service Authentication.
As Wayne Yang said, customization of the login page is limited to logos and some text.
I'm not sure if you can use the "Easy Auth" for APIs.
You might need to actually implement the authentication in your app.
In that case your API would validate the incoming JSON Web Token so that its signature is valid and that the audience and issuer are what is expected.
Most frameworks have JWT authentication available, so it mostly comes down to configuring that properly.
I've programmatically registered a web application in WAAD through POST HTTP Request. The HTTP response returns the client Id however am unable to get the client secret. Is there a way from Graph API could get the client secret for the registered apps.
This scenario is not supported. But you can add extra one client secret and both will be valid.