I have created a Xamarin.Forms project and a Table API project. Both have been created through the QuickStart menu in Azure Portal.
I have configured an Azure AD in my portal and I can successfully retrieve a token from the AD through my XForms app. But when I try to login to the Table API using the LoginAsync method from the MobileServiceClient, I receive a "You do not have permission to view til directory or page."
I have been looking through the following guides but with no luck.
How to configure your App Service application to use Azure Active Directory login
Add authentication to your Xamarin.Forms app
How to: Work with authentication
I have also look at the following question but didn't find a solution.
Cordova AAD server flow authentication hangs on Android and iOS
I Am thinking that I might be missing some specific authentication on the Table API project?
Here is my code and setups:
PCL PROJECT IN XFORMS
var ar = await authContext.AcquireTokenAsync(Constants.GraphResourceUri, Constants.ClientId, userCredintials);
JObject payload = new JObject();
payload["access_token"] = ar.AccessToken;
var client = new MobileServiceClient(Constants.ApplicationUrl);
var user = await client.LoginAsync(MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, payload);
The Constants.ClientID is the ClientId of the Native Client app and not the webserver. If I switch it around I get a 404.
EXAMPLE OF CONTROLLER FROM TABLE API PROJECT
[Authorize]
public class StatisticController : ApiController
TABLE API StartUp.cs CONFIGURATION
public void Configuration(IAppBuilder app)
{
app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions());
ConfigureMobileApp(app);
}
MOBILE SERVICE AUTH SETUP
SINGLE SING-ON AD SETTINGS
NATIVE CLIENT APP SETTINGS
EDIT
I can duplicate the error through PostMan with the following setup:
I tried to include a "X-ZUMO-AUTH" header with the value of the access_token but with the same result. Still no permission. I also tried to exclude every header in the POST request but with no changes. Does this mean that POST requests from my mobile app or Postmand is not allowed?
If I manually browse to mysite.azurewebsites.net/.auth/login/aad in a browser, then I can log in with the users from my AD. So it seems that the AD is communicating correctly with the service and vise versa.
FIXED IT
Great thanks to mattchenderson! As he suggests I should change the constant GraphResourceUri to the client id of my service instead of the normal graph api. Along with adding a single instance of the client I can now successfully log in to my service.
POST requests are allowed, and I use Postman all the time for testing.
The most common cause of an issue like this is an audience validation issue. The audience is a property of the AAD token which says for what resource is this token valid. Given the code above, I would expect the audience to be equal to Constants.GraphResourceUri. My guess is that this is actually the graph API, and not your application, and that would cause a validation failure, although I would expect it to happen when you call LoginAsync(). I would suggest trying the web application client ID instead (that's the Client ID from the "MOBILE SERVICE AUTH SETUP" screenshot).
For an easier time debugging, you can take your AAD token to something like http://jwt.io, and that will help you see the token properties. "aud" is expected to the same as the client ID of the application as registered in the portal, and you want the issuer fields to match up as well. Make sure the token is not expired either.
When using the token to access protected APIs, there are two ways to provide it:
Use the token returned as part of LoginAsync() in the X-ZUMO-AUTH header of your request. This will automatically be done by the SDK for table operations using the same MobileServiceClient.
Use the AAD token directly according to the bearer token spec. That is, include it in the Authorization header, with the value "Bearer ", replacing token with your value.
Also, I see in your code that you are creating a new MobileServiceClient for the login operation. This is something we generally discourage, as the login information is attached to the MobileServiceClient object. If you lose a reference to that, you lose the login information (and a few other settings), and they won't be applied to your table operations. The recommendation is to use a single instance that is referenced elsewhere - for example, in Xamarin, a static variable within your shared code.
Related
I created an Api in azure and recently tried to change to authentication method to access it via OAuth2.
I requested a token using https://login.microsoftonline.com/[TENANT]/oauth2/v2.0/token/ and tried to use it to access my api via postman.
Then I tried to use the received token to make a request to my api:
I used Postman's Authorization pane to specify OAuth2.0 as the authentication method and set the Grant Type configuration to "implicit" and sent a request.
Configured like this, the request goes through using the "http" version of my api but as soon as I try to use the "https" version, I get a 401 error "Unauthorized".
Have I configured my api wrong ? Or am I using the wrong url to authenticate ?
Thanks a lot for your time.
After a lot of research I found out what was wrong :
I had to add the application ID in the allowed token audiences of identity provider (in the azure app service, navigate to authentication > locate the identity provider > click on edit > at the bottom of the page add the your app registration's application ID. For good measure I also added api://[APPLICATION ID]/.default and api://[APPLICATION ID]
There was still some authentication code left in the source code of my api. When I was trying to connect I sometime had a response which consisted of HTML titled "Sign in to your account". It was caused by a segment of code in the startup.cs file of my api which verified the user who made the request against my Azure AAD. After removing it I no longer had the error
I'm authenticating with a service principal that was setup by another developer. I'm trying to authenticate against an internally developed API. The ASP is working when the other developer uses the SDK to authenticate. But when I try with Postman, I'm getting a 401 with this error.
The issue is that I don't really know which resource to use. I believe the client ID, secret, and scope is correct. But I can't seem to find any info on the type of resource to use. Is there any way to determine this for an internally developed API? I've used a ton of publicly available ones. Just as testing, as I can't find any info. And leaving it blank does not work.
Assuming you have two applications created in azure ad app registration, one representing the client application and the other representing the api application, (or in app registration you must have selected the required client application) and then you must be using the client application to call the Web api application.
NOTE: When you call web API , make sure you are sending Access token (not Id token)
you track the token you get in jwt.io .
Azure AD audience must match the “aud” claim when.
The Audience must equal the AppId or client id set for the application.
Check iss value of token in jwt.io and see the version of login url. If it is v2 set manifest json in the app registration for the API to 2, as it may be by default be 2.
"accessTokenAcceptedVersion": 2
In the app registration if your exposed api is something like : api://xxxx-xxx-xxx ,then the client id in appsettings.json of your app must be the same.
Note:Client id may be configured differently according to application.
If above doesn't work try client ID : instead of api://
You may need to grant application permissions to your client applications (this is the role permissions you define yourself, you can find it in My APIs when you add permissions).Then you need to click the admin consent button to grant administrator consent for this permission.
Here I exposed scope >> api://xxx-xxx-xxx/access_as_user. Make sure to use the same scope configured in portal is included in application configuration. The scope should include the exposing resource's identifier (the Application ID URI) in the code too.
Here Ex: scopes: "api://xxxx-xxx-xxxx/access_as_user "
In postman Set Authorization header to refer a global variable 'Bearer {{bearerToken}}' and add the authorization data to Request Headers,
If you are using postman call back uri , uncheck the authorize using browser for callbackurl in postman configuration.(see enable-azure-ad-authentication| csharpcorner )
I am trying to call a CDN Purge's Azure REST API url from Microsoft Flow.
I found HTTP - HTTP as the best action to use as Azure with HTTP sounds to be specialized on accessing resources not on (just) calling.
I created a Web app / API application in Azure Active Directory for this purpose.
The API calls need to be authenticated so I chose Active Directory OAuth.
I filled in the Tenant id into Tenant, chose Secret as Credential type and put a application's password (Keys) into the Secret field.
However, I am lost what to put into Audience and Client ID field.
I tried to search docs but did not find any relevant results. I presume one of those should be the App Id.
What to put into the Audience and Client ID fields and how to find the values?
Is there anything else required to do to make this working (like setting a permission to allow purging the CDN, updating manifests, assigning roles)?
PS: I am getting BadRequest. Http request failed as there is an error getting AD OAuth token: 'AADSTS50105: Application '<appId>' is not assigned to a role for the application '<appIdUri>'. in my most recent attempt.
The audience is the value of App ID URI that you registered (homepage below image)
The Client Id is nothing but the Application ID
I have been researching on Azure Mobile app service and I am freaking out because I think I had it all wrong.
I have one Azure Mobile App service and issue is I am trying to implement "custom" authentication for it (the reason for custom authentication is that I have a web app and web API which uses the same database and send REST requests to mobile service app to update database and both of them use asp.net identity)
But before I implement custom authentication in mobile app service, I just can't get my head around that even though the authentication is custom and I am manually checking users, once the token is generated and user is authorised, the user has access to all the data in the table. So if I am user1 and login, mobile app service will authenticate me and once I have the auth token I can simply do REST request to do anything to all the data.
How do I restrict that the generated token is only used to CRID only that user's data where in my table I have UserId column also.
I am very confused. any help will be appreciated.
How do I restrict that the generated token is only used to CRID only that user's data where in my table I have UserId column also.
Per my understanding, you could follow Per-User Data and leverage the following property to retrieve the current UserID from the incoming Easy Auth token:
public string UserId
{
get
{
var principal = this.User as ClaimsPrincipal;
return principal.FindFirst(ClaimTypes.NameIdentifier).Value;
}
}
For the complete tutorial about handling CURD operations which need to be limited to the user who generates the token, you could follow Data Projection and Queries.
so far I've not been able to get this working with the bot framework. I spent all day but only managed to get .net api example (https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) working with AD B2C. I'm not sure where it grabs the bearer token that I want to pass to BotUserData...
I've tried following https://azure.microsoft.com/en-us/blog/bot-framework-made-better-with-azure/
but in reality the solution does not build successfully and I've resorted to just taking code from there and into my bot framework sample template....however, when it asks me to login through MS and I do, I am not able to proceed and it doesn't seem like that blog is using the AD B2C policies.
so how do you integrate AD B2C with Bot Framework? Is it possible to call /Account/SignIn URL from bot framework to authenticate the user? Afterwards, how would you capture the token and pass it to BotUserData?
You might want to take a look to the Facebook Auth sample to get an idea of a potential flow for the Auth scenario. For Azure AD, you need to do a similar flow.
Let's say your user send a "Login" message to your bot. The bot should respond with an auth URL and ask the user to login to the service using that URL. You can use the GetAuthorizationRequestURL method of ADAL for that.
Then you will have a Web API which will basically expose an endpoint that will be the reply URL of Azure AD. Once the users completes the login, a message will be posted to your Web API where you will be able to get the authorization code and perform the calls to get the Access Token. After that, you can just do the same they are doing in the Facebook Sample Web API which involves resuming the conversation with the Bot, sending a message with the access token (so it can be persisted in the PerUserInConversationData bag (check this line of code).
After that you have the access token available to perform any call that requires an access token.
Update
There are two new samples that you might want to take a look since they are implementing the workflow being discussed.
GraphBot from the BotBuilder repo.
AuthBot from Mat Velloso
Hope this helps.
Follow this tutorial for Bot side code development, i focus on configuration at B2C and Azure level here:
OAuth Connection
Client id
This is taken from the Application ID field in your B2C app's properties. It's the equivalent of a Microsoft app ID taken from any other AAD app registration.
Client secret
This is generated using the steps in this tutorial.
Select Keys and then click Generate key.
Select Save to view the key. Make note of the App key value. You use the value as the application secret in your application's code.
Use AAD V2 configuration in oAuth settings in bot channel registration - new oauth connection settings.
Fill the above details by following the steps and values we got from them.
Authorization/Token/Refresh URL
I followed on this one with
https://login.microsoftonline.com/tfp///oauth2/v2.0/authorize
for the Authorization URL and
https://login.microsoftonline.com/tfp///oauth2/v2.0/token
for the Token and Refresh URL's.
For I used the URL format (kyleorg.onmicrosoft.com) rather than the GUID format, but using the GUID also seems to work.
is the name of a user flow, like B2C_1_userflow. I created one with this tutorial.
Scopes
Using the scopes openid offline_access I am able to sign in successfully, but to my astonishment the token returned is empty.
Then I found this document which suggests using the client ID itself as a scope.
When I reuse the value from the Client id field in my Scopes field, a token is returned successfully and my bot is able to use the connection.
You can combine this with other scopes as needed, but for the sake of experimentation I highly recommend getting the simplest implementation to work first.
Let me know if these instructions work, and if they don't then we'll see if the difference lies in how we've set up our B2C apps.
As a bonus, I should mention that after you get a token you can paste it into https://jwt.ms/ to decode it and see if it recognized your B2C user correctly. Always refresh the page when pasting a new token to make sure it doesn't keep showing you the information from the last token.
Referred this document.