Why can't I access my Azure Function when it requires authentication? - azure-active-directory

(I apologize for the length of this question; I wanted to be thorough.)
I'm new to Azure and am trying to set up a "serverless" API which requires authentication. I have a Function which behaves correctly when authentication is not enabled (basically just "Hello, world" in Node.js). However, when I enable authentication, the only response I get is:
You do not have permission to view this directory or page.
To enable authentication, I:
Went to Azure Active Directory in the Azure portal.
Went to App Registrations.
Created a new registration for my Functions app.
Added a Web redirect URI of https://<myapp>.azurewebsites.net/.auth/login/microsoftaccount/callback.
Created a new client secret for my app.
Went to my app from the Dashboard, selected the "Platform features" tab, and clicked on "Authentication / Authorization".
Enabled "App Service Authentication".
Configured the Microsoft authentication provider with the above registration's Application ID and client secret.
Set "Action to take when request is not authenticated" to "Log in with Microsoft Account".
At this point, I can no longer access my API endpoint without authentication (as expected). I then configured Postman to obtain a token by:
Selecting the Authorization tab.
Setting the Type to "OAuth 2.0".
Clicking "Get New Access Token".
Setting the following values:
Grant Type: Authorization Code
Callback URL: https://<myapp>.azurewebsites.net/.auth/login/microsoftaccount/callback (the same as I entered into my App Registration, above).
Auth URL: https://login.microsoftonline.com/<Directory (tentant) ID>/oauth2/authorize?resource=<Application (client) ID>
Access Token URL: https://login.microsoftonline.com/<Directory (tentant) ID>/oauth2/token?resource=<Application (client) ID>
Client ID: <Application (client) ID>
Client Secret: <Client secret>
Scope: <empty>
State: <empty>
Client Authentication: Send as Basic Auth Header
Clicking the "Request Token" button.
Logging in as myself in the window which pops up. (Only happened the first time; presumably my credentials are being cached somewhere.)
Clicking the "Use Token" button.
Clicking the "Preview Request" button.
When I then click "Send", I get the error above. If I disable authentication or change "Action to takeā€¦" to allow unauthorized requests, it begins working again (but doesn't, of course, require authentication). I've run the JWT that Postman receives through JWT.io and the payload looks reasonable, as far as I can tell:
{
"aud": "<Application (client) ID>",
"iss": "https://login.microsoftonline.com/<Directory (tentant) ID>/v2.0",
"iat": 1558488698,
"nbf": 1558488698,
"exp": 1558492598,
"aio": "<base64? data>",
"azp": "<Application (client) ID>",
"azpacr": "1",
"idp": "live.com",
"name": "Ben Blank",
"oid": "<a GUID I don't recognize>",
"preferred_username": "ben.blank#gmail.com",
"scp": "User.Read",
"sub": "<base64? data>",
"tid": "<Directory (tentant) ID>",
"uti": "<base64? data>",
"ver": "2.0"
}
Can anyone tell me what I've done wrong?

You need to register Postman as a client app in AAD and give it permission to call your API, kind of like here except you will give it permissions to access your API rather than AAD Graph as in the link. Your Postman will need to be configured to use that apps client id and secret to get the token. Right now you are using Postman to ask for your API app to get an access token to itself. Most likely you app is not configured in AAD to call itself! (does not make sense anyway).

You are using Microsoft Account as the Authentication Providers. The way you get the access token is regarding Azure Active Directory, not Microsoft Account.
When you access your function url https://tonytest4.azurewebsites.net/api/HttpTrigger1?name=test, you will redirect to the login page. You will find the url is https://login.live.com/oauth20_authorize.srf?. After entering the correct credential, you will be able to access your function.

Related

Why is SignUpSignInPolicyId required for an API?

This sample here shows providing a SignUpSignInPolicyId https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/4-WebApp-your-API/4-2-B2C
See the appsettings.json for the service (Web API):
"AzureAdB2C": {
"Instance": "https://fabrikamb2c.b2clogin.com",
"ClientId": "90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6",
"Domain": "fabrikamb2c.onmicrosoft.com",
"SignedOutCallbackPath": "/signout/B2C_1_susi_reset_v2",
"SignUpSignInPolicyId": "B2C_1_susi_reset_v2"
//"CallbackPath": "/signin/B2C_1_sign_up_in" // defaults to /signin-oidc
},
I am confused what this does with an API, the API is protected by OAuth2 JWT it cannot control sign up or sign in at all. It just takes a token and validates it.
Why does it need to know anything at all about a sign up or sign in policy?
When I tried to run the application which calls api with policy ,I can login and open the redirect to app.
Appsettings.json
{
"AzureAdB2C": {
"Instance": "https://kavyab2c.b2clogin.com",
"ClientId": "xxxxxxx",
"Domain": "kavyab2c.onmicrosoft.com",
"SignedOutCallbackPath": "/signout/B2C_1_susi",
"SignUpSignInPolicyId": "b2c_1_susi",
"ResetPasswordPolicyId": "b2c_1_reset",
"EditProfilePolicyId": "b2c_1_edit_profile" // Optional profile editing policy
//"CallbackPath": "/signin/B2C_1_sign_up_in" // defaults to /signin-oidc
},
Even without policy it redirected to page.
But to obtain claims or reach the particular controller action or access an api, it requires user authentication if one needs to protect API.
Note:
SignUpSignInPolicyId should not be omitted when calling an Azure AD B2C protected API. If it is not specidfied, the API will not know which user flow to use and cant authenticate the user and gives error.
If custompolicy is used instead of userflow, the SignUpSignInPolicyId
parameter can be omitted, and the created custom policy can be used
to authenticate and authorize users directly by making use of their
username and password credentials.
Reference: Cloud authentication with Azure Active Directory B2C in ASP.NET Core | Microsoft Learn

Create Microsoft teams meeting through API

In Azure Active Directory I've registered a new app and given it the Read and create online meetings permissions. I've granted admin consent for the permission and now I'm trying to create a meeting through the command line.
I generated a client secret for the app.
Then I'm requesting a access token using my tenant GUID, client ID of the app and client secret I generated. This gives me back a jwt. When I decode the JWT amongst the roles I can see "OnlineMeetings.ReadWrite.All" which gives me hope that I can actually create meetings using this bearer token.
I then send a POST request to https://graph.microsoft.com/v1.0/users/<my-user-guid>/onlineMeetings
with the following body:
{
"startDateTime":"2021-03-16T14:33:30.8546353-07:00",
"endDateTime":"2021-03-16T15:03:30.8566356-07:00",
"subject":"Application Token Meeting",
"participants": {
"organizer": {
"identity": {
"user": {
"id": "<my-user-guid>"
}
}
}
}
}
and the response comes back with
"code": "Forbidden",
"message": "Application does not have permission to Create online meeting on behalf of this user.",
Am I missing something?
Edit:
As some of the comments have suggested I should create an application access policy. So I'm following the documentation which asks me to Connect using admin credentials
When i run Connect-MicrosoftTeams -Credential $userCredential with my account it fails with the following error:
Connect-MicrosoftTeams: accessing_ws_metadata_exchange_failed: Accessing WS metadata exchange failed: Response status code does not indicate success: 406 (NotAcceptable).
Connect-MicrosoftTeams: accessing_ws_metadata_exchange_failed: Accessing WS metadata exchange failed
Connect-MicrosoftTeams: Response status code does not indicate success: 406 (NotAcceptable).
Connect-MicrosoftTeams: : Unknown error
But this is what is confusing me. I don't really know if I'm trying to login with the correct account. I'm using my personal account on azure which is (afaik) not a business account with skype for business.
I'm running the commands to log in on the azure portal's PowerShell interface. Am I supposed to run this on my local machine instead?
I think I'm not fully understanding what all of the moving parts are that need configuration.
Can I add those application Access Policies in the azure portal interface somewhere?
According to the api documentation, make sure you grant the OnlineMeetings.ReadWrite.All application permission to the application. Then you need to use the client credential flow to obtain an access token.
Please note that when you create an online meeting with an application token, administrators must create an application access policy and grant it to a user, authorizing the app configured in the policy to create an online meeting on behalf of that user (user ID specified in the request path).

Azure AD B2C. ROPC flow error The application associated with client id has no registered redirect URIs

The application associated with client id 09ac92da-a796-4cd9-973b-c97756____ has no registered redirect URIs
Description
I followed the steps described in https://learn.microsoft.com/en-us/azure/active-directory-b2c/configure-ropc?tabs=applications.
When attempting to obtain the token in Postman using ROPC I'm getting
{
"error": "invalid_request",
"error_description": "AADB2C90007: The application associated with client id '09ac92da-a796-4cd9-973b-c97756____' has no registered redirect URIs.\r\nCorrelation ID: e85003c3-cfd5-43ad-a74b-efa5c1ea6525\r\nTimestamp: 2019-12-06 19:47:42Z\r\n"
}
I should not be asked for a redirect URIs.
My POST is as follows:
URL: ''https://mytenant.b2clogin.com/mytenant.onmicrosoft.com/oauth2/v2.0/token?p=B2C_1_ROPC_Auth"
username: some_username_of_a_user
password: its-password
grant_type: password
scope: openid offline_access 09ac92da-a796-4cd9-973b-c97756____
client_id: 09ac92da-a796-4cd9-973b-c97756____
response-type: token id_token
I didn't reproduce your issue by following this document. Here are the main steps for your reference.
1.Create a resource owner user flow
2.Register an application(It is an application under Azure AD B2C, not Azure AD)
3.Test the user flow
This error generally occurs because you still need to configure some application claims in the b2c directory user flow to allow complete access to the application.
You need to make sure that the right versions of the authentication are in the reply url (likely extension v2.0) and that the reply URL is configured in the application and in the code.
Please look to the documentation for the reply URL schema that you would need to follow: https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-register-applications?tabs=applications#register-a-web-application
If you still run into this issue let me know and I can reach out to the correct product team contacts, as sometimes this can happen due to breaking changes on our end.

Can I get an id_token from Azure AD for my app?

Using the client_credentials flow in Azure AD, I am unable to retrieve an id_token for my app.
I am experimenting with the Azure AD OAuth/OpenID endpoints, and running into some questions.
I create a simple app with minimal config through the Graph API (a beta endpoint, but still). I have removed all the headers and anonymised in code snippets below:
curl -X POST \
https://graph.microsoft.com/beta/applications \
-d '{
"displayName": "App Name",
"passwordCredentials": [
{
"endDateTime": "2299-12-30T23:00:00Z",
"startDateTime": "2019-02-14T20:19:14.686691Z",
"secretText": "<SOME KEY>",
"displayName": "Client Secret"
}
]
}'
In the response from Azure AD, I get an appId:
{
"#odata.context": "https://graph.microsoft.com/beta/$metadata#applications/$entity",
"id": "<SOME GUID>",
"deletedDateTime": null,
"isFallbackPublicClient": null,
"appId": "<SOME GUID>",
...
This is enough for me to be able to retrieve an access_token from the v1 OAuth endpoint:
curl -X POST \
https://login.microsoftonline.com/tenant_id/oauth2/token \
-d 'client_id=appId&client_secret=secretText&grant_type=client_credentials'
Response:
{
"token_type": "Bearer",
"expires_in": "3600",
"ext_expires_in": "3600",
"expires_on": "1550220412",
"not_before": "1550216512",
"resource": "00000002-0000-0000-c000-000000000000",
"access_token": "<JWT access token>"
}
Since I didn't specify a resource in my call, I get the default Graph API resource.
Now, what I also would like to get is an id_token for my app. I have been able to get these tokens from other OpenID providers. However, the OpenID Connect Core spec. gives me reason to think that id_tokens are for end users only, not apps:
"The ID Token is a security token that contains Claims about the Authentication of an End-User by an Authorization Server when using a Client, and potentially other requested Claims"
(From https://openid.net/specs/openid-connect-core-1_0.html#IDToken)
Adding resource=openid to the POST to the token endpoint above won't work, since openid is a scope, not a resource.
Switching to the v2 endpoints, I get access to a scope parameter. I can obtain an access token from there by setting scope=https://graph.microsoft.com/.default, explicitly requesting the access I got by default through the v1 endpoint.
However, setting the scope to for instance scope=https://graph.microsoft.com/.default openid does not give me an id_token for my app, and the access token looks identical to the previous call.
Trying just scope=openid gives me the following error from Azure AD:
AADSTS70011: The provided request must include a 'scope' input parameter. The provided value for the input parameter 'scope' is not valid. The scope openid is not valid.
All this combined leads me to believe that the OpenID providers I have used and have issued id_tokens through the client_credentials flow are breaking the spec, and that id_tokens can only be obtained for end users (using the authorization_code flow gives me an id_token from Azure AD for myself without any issues).
Is this a correct conclusion, or can I force Azure AD to issue id_tokens to apps as well as end users?
An id_token is issued when a user signs-in. Client credentail flows have no user, so no id_token is issued.
you'd need to use a flow like authorization code grant or openID connect to sign a user in. The response will have a id_token.
You cannot use the client credentials flow to get the id_token for app-only, it only returns the access_token.

Calendar endpoint returns OrganizationFromTenantGuidNotFound

I'm currently trying to achieve in Node.js a direct login to Calendar/Users using Microsoft Graph.
What I've done so far are the following:
Login on the account and make sure that it currently has a calendar (the email is registered under #outlook.com).
Go to azure portal and create a new AAD name "Calendar Api" web API with return
URL http://localhost:3000
AAD -> App Registration -> Name: Test, reply url: localhost:3000, Required Permissions for Microsoft Graph (Users Read/Write, Calendars Read/Write), Windows AAD (offline_access), Grant Permissions, Generated a new secret key with no expiry date.
Went to Postman and started to generate a new token based on the following URL:
https://login.microsoftonline.com/{APP_ID_URI}.onmicrosoft.com/oauth2/v2.0/token
grant_type : client_credentials
client_id : {app_id}
client_secret : {app_secret}
scope : https://graph.microsoft.com/.default
And I a 200 OK with a token.
Upon inspecting the token:
"aud": "https://graph.microsoft.com",
"roles": [
"User.ReadWrite.All",
"Calendars.Read",
"Calendars.ReadWrite"
],
GET ON -> https://graph.microsoft.com/v1.0/users/ with Authorization Bearer and the above token will return a code status 200 along with the user account I've used in step 1.
GET ON -> https://graph.microsoft.com/v1.0/calendars/ with Authorization Bearer and the above token returns "Resource not found for the segment 'calendars'."
GET ON ->
https://graph.microsoft.com/v1.0/users/{user_id}/calendars OR /calendar OR /calendarView:
"code": "OrganizationFromTenantGuidNotFound",
"message": "The tenant for tenant guid '104fdcd9-76d1-4122-89a0-30cb00722de2' does not exist."
I don't really have a code because I am using POSTMAN to test the API first.
I would expect to get a list of events or a list of calendars instead of an error.
After some digging I found out what the problem was, so here is the full solution to this question.
You need a microsoft office 365 account with subscription, can get this by applying for one on office 365 develop.
Upon creating one, follow the instructions and add the apps to it.
Go to Azure Portal and log in with your office 365 account.
Create an app under AAD -> App registration
Follow step 4 and 5 of this question.
Try to access https://graph.microsoft.com/v1.0/users/{user_id}/calendars.

Resources