A little background:
I have a React SPA connected to a C# Dotnet Server. I am using OAuth with AzureAD as an identity platform.
I am creating an application that can be logged in by anyone with either an Organisation, Microsoft or personal account.
There are no restrictions in the tenant. I have enabled access for all users.
Permissions wise I have made sure all permissions don't require admin consent to allow all users including personal user (e.g xxxx#outlook.com) to sign in.
I have setup the react code to use MSAL to login & generate the token to be used in my API calls. Here is my authConfig.js file:
authConfig.js
NOTE: I am able to successfully login using the tenant admin account. This doesn't cause the error. However, using a newly created outlook account I will get a consent to accept and after that the error still occurs.
THE PROBLEM:
After signing in and fetching the token which are done successfully, when trying to use the token in the authorization header in my API calls it seems to 500 error. Looking at the server console it spits this error message out:
500 Error upon trying to use the generated MSAL token
Has anyone got a clue how to resolve this?
Related
I'm pretty new to how this should work, so bear with me...
All I want is for when I login to webapp1, my webapp2 already sees I'm logged in and doesn't require me to login or re-authenticate. Should be simple, right?
Stack/flow is :
dotnet core
C#
Azure AD
oidc
To keep things simple, I created/registered my two webapps from within VS
(i.e. VS registered a web app on AzureAD for me from within VS). Doing it this way, the apps get created within AzureAD with the appropriate redirect URIs as well as enabling ID Tokens for the auth endpoint. Magic.
I did this for WebApplication1 and WebApplication2. This also automatically creates for me an AzureAD section specific to my two web apps registered in AzureAD.
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "mydomainhere.onmicrosoft.com",
"TenantId": "my-tenant-guid-here",
"ClientId": "my-client-quid-here",
"CallbackPath": "/signin-oidc"
},
All is great thus far.
When I startup webapplication1, it starts up and immediately asks for me to pick an account:
Great, I select the appropriate account, grant consent, and then am taken to my webapplication1:
Now for brevity's sake, Imagine I do the exact same thing for WebApplication2. However, when I start it up, I'm again asked to pick an account and grant consent. I get that, I've never granted consent yet. So fine, after I've picked an account and granted consent I'm taken to my WebApplication2.
However, here's the rub. When I simply refresh my WebApplication1, that site now again asks for me to pick an account before allowing me to interact with the WebApplication1.
Why?? I want SSO to work. What am I missing here? I want for WebApplication1 and WebApplication2 to no longer require me to reauthenticate unless I sign out on one of those sites and/or the token expires. I don't get it.
The “choose an account” prompt can be bypassed by using OAuth parameters HSU=1 and Login_Hint parameters. Currently this only works with the v1 endpoint though and does not yet work with the v2 endpoint. The product team is working on a release for the v2 endpoint.
See: Bypass Choose your account and Automatically select an account in Azure AD
As for the SSO aspect, the user should remain signed into both apps if you have the applications configured correctly. Open ID Connect issues access tokens and refresh token to the users who haven authenticated to the app. If another app is accessed in the same browser, the user who is logged into the first application should automatically be logged in because the browser maintains the user's session. The session for that user will be maintained until either the browser is closed or the access token expires (after 1 hour by default).
Since it sounds like you are using the same tenant you will be able to stay signed into both apps needing to enter the credentials twice using the OIDC sample.
This is an old video my colleague and I made using the older OIDC Azure sample, but it shows the basic setup for how this works.
Here is a more recent quickstart guide for achieving SSO.
Additional resources:
Multiple Azure AD web apps Authentication
SSO to multiple sites
Problem Statement:
I'm trying to create a module in C# console application that I intend to plug and use in Azure Bot once it is operational. I want to connect my bot with Azure DevOps. I am able to do that with PAT token but I need the bot to only display the resources from DevOps on which the logged in user has access.
Attempts:
I am able to get the necessary details using PAT token. It gives me all projects irrespective of the logged in user details.
I have tried to use the Azure AD token for the logged in user but it gives me unauthorized error on trying to use it to invoke Azure DevOps REST APIs
Referred this article but I am unable to get the auth code or token silently.
To summarize, I'm basically looking to:
Obtain a user token for Azure DevOps silently (without user confirming with a click)
Use REST APIs to fetch details like projects, work items etc.
A Personal Access Token inherits the permissions from the user that created it. So if you, as a project collection administrator, create a token, that token has the samwe permissions as you do.
Unfortunately there is no public REST API that you can use to create a token at runtime. They have to be created by a logged in user through the portal.
Another option is using OAuth. OAuth asks the user to login and then gives you a token that you can use in the REST APIs. Unfortunately that doesn't meet your criteria where a user doesn't have to do anything,
The only other way I see is adding the users to the resources they have permissions for. Then from your REST API you can use the admin PAT to check their permissions and then retrieve only what they are allowed to see. Which also isn't really pretty :-(
I am currently building an API which requires OAuth2, but cannot find a library to use that will handle the single sign on in a native mobile app via RESTful API only. Most I've found only have a web popup, which has been vetoed for this project. B2C, which is currently functioning, is not capable of using ROPG. Is there a way to easily set this up with another library using C#.NET and Azure?
UPDATE:
Attempting to use B2C per Fei Xue answer below, we got to the point of getting an access token from Microsoft Graph.
In the body of the POST, we did the following:
resource=https%3A%2F%2FGraph.windows.net&client_id=[B2C Settings -
Applications -
AppId]&grant_type=password&username=rob%40[tenant].onmicrosoft.com&password=[password]&client_secret=[B2C Settings - Applications - App Key - client_secret]
Our error with the namespace was due to the usernames we were trying. This is a B2C tenant using email as the username and that was the reason for the namespace error. The only way we got past that error was to create a B2C user with the email address ending in the tenant, like so:
rob#[tenant].onmicrosoft.com
We are getting an access token now, but that token does not authenticate with our azure app service api app, which was the original goal.
What we are trying to accomplish is to send the username and password that is valid for a B2C signin and get an IdToken or Access Token that is valid for the api app. The api app connects to B2C via App Service Authentication settings configured for AAD with the Client ID and secret setup from the B2C Settings Application.
UPDATE:
Attempting to pass through the graph.windows.net token for authentication in our Azure web api, we added in the https://Graph.windows.net allowed token audience in our App Service – Authentication – Active Directory Authentication configuration.
However, passing the graph access token in the Bearer header to the API still results in
“Authorization has been denied for this request”.
Found out that if we make the Issuer Url blank like in the example below, it now accepts the Graph token!
However, this causes issues when trying to hit
https://[our_web_app].azurewebsites.net/.auth/login/aad
It goes to the common Microsoft login now. Previously it directed to our B2C sign up in policy because the Issuer Url was set to:
https://login.microsoftonline.com/[tenantname].onmicrosoft.com/v2.0/.well-known/openid-configuration?p=[B2C_SignUpIn_Policy]
In fact, if we also pull up the policy from within our app (which was working before removing the Issuer Url) to the sign in policy, we can sign in, but that returned Access Token now always comes back as Unauthorized in the web API calls.
Should the Issuer Url be left blank?
Also, since making the Issuer Url blank, the server takes much longer to respond to API calls when we send a request using a Graph access token in the Header Authorization Bearer. It went from taking about 1-2 seconds (using a valid B2C access token obtained from MSAL or the web login above) to taking about 10-15 seconds to respond that it is an authenticated request. That kind of speed is a show stopper for us. Does validating a graph call in this manner normally take this long?
The feature is now available in preview and works pretty well:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/configure-ropc
Important note: The POST url mentioned in the documentation is wrong.
https://login.microsoftonline.com/{{Aad_Tenant}}/b2c_1_ropc_auth/oauth2/v2.0/
Must be:
https://login.microsoftonline.com/{{Aad_Tenant}}/oauth2/v2.0/token?p=b2c_1_ropc_auth
The calling application must have native client enabled, otherwise you will get this error:
AADB2C90224: Resource owner flow has not been enabled for the application.
The Azure AD B2C has already support the Resource Owner Password Grant flow, you can send the HTTP request like below to using this flow:
POST: https://login.microsoftonline.com/{tenant}/oauth2/token
resource=https%3A%2F%2FGraph.windows.net&client_id={client_id}&grant_type=password&username={userName}&password={password}&client_secret={secret}
Note: this flow only work for the local accounts as social identity providers(Facebook, Google, etc) don't support this.
Update
The token above is acquiring the token for https://graph.windows.net. To pass through the authentication of web API which protect by Azure AD, we need to specify this as the ALLOWED TOKEN AUDIENCES like figure below:
Update to the answer from #AlexAIT.
The URL in the documentation now works for AD B2C.
https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/B2C_1A_ROPC_Auth/oauth2/v2.0/token
https://learn.microsoft.com/en-us/azure/active-directory-b2c/add-ropc-policy?tabs=app-reg-ga&pivots=b2c-user-flow#test-the-ropc-flow
If you get the error:
AADB2C90224: Resource owner flow has not been enabled for the
application
Navigate to application -> Authentication and select Enable the following mobile and desktop flows:.
Wait a few minutes and then it will start to work.
Github thread:
https://github.com/MicrosoftDocs/azure-docs/issues/50330
I work with Rob, and we did finally get the call to work with
https://login.microsoftonline.com/[tenant_ending_in_onmicrosoft.com]/oauth2/token
In the body of the POST, we did the following:
resource=https%3A%2F%2FGraph.windows.net&client_id=[B2C Settings - Applications - AppId]&grant_type=password&username=rob%40[tenant].onmicrosoft.com&password=[password]&client_secret=[B2C Settings - Applications - App Key - client_secret]
Our error with the namespace was due to the usernames we were trying. This is a B2C tenant using email as the username and that was the reason for the namespace error. The only way we got past that error was to create a B2C user with the email address ending in the tenant, like so:
rob#[tenant].onmicrosoft.com.
We are getting an access token now, but that token does not authenticate with our azure app service api app, which was the original goal. What we are trying to accomplish is to send the username and password that is valid for a B2C signin and get an IdToken or Access Token that is valid for the api app. The api app connects to B2C via App Service Authentication settings configured for AAD with the Client ID and secret setup from the B2C Settings Application.
UPDATE:
If I add ?p=[B2C SignUpIn Policy] to the POST, then we get the following error:
AADB2C90224: Resource owner flow has not been enabled for the
application.
I am currently prototyping an authentication model for a series of cloud based micro services and have run into a wall when trying to obtaining a token from Azure AD on behalf of the authenticated user. I feel I am missing something obvious so I am hoping someone can point me in the right direction.
Overview
My prototype consists of two applications:
An Asp.MVC base UI
A WebAPI based data service.
Both applications are hosted in azure and use Azure's active directory for access management. In azure, I have set up two AD instances:
Service Directory: This is the master directory where all applications are registered.
Tenant Directory: The AD instance for the tenant. Going forward, there would be one of these per tenant.
Both the UI and data service are registered in the service directory and set to multi-tenant. The UI authentication is based on Vibronet's multi-tenant sample and correctly pushes the users through the consent grant flow when they first log in, and then registers the UI application with the users AD instance. During the consent grant, the UI requests the following permissions:
Access your organization's directory
Enable sign-on and read users' profiles
Read and write directory data
Read directory data
The user is then redirected back to the UI application and I can successfully view the users claim information at this point. So, up until this point I believe everything is configured and working correctly.
The Problem
Once the user is authenticated, the UI application should then obtain a token on behalf of the current user to access the back-end data service and this is where the problem lies.
The authentication for the data service is based on WebApi-On-Behalf-of sample however whenever I attempt to obtain the token, I get the following error:
No permission to access user information is configured for [AppGuid] application, or it is expired or revoked
Given the permissions granted during the consent flow, however, I believe it should have permissions to access the tenant AD instance and have tried giving the UI application all application and delegated permissions available in AD and re-running the consent flow but still get the same result.
My code for obtaining the on-behalf-of token is as follows:
ClientCredential uICredentials = new ClientCredential(StartUp.UiClientId, StartUp.UiSecret);
BootstrapContext bootStrapContext = GetBootstrapContext();
UserAssertion userAssertion = new UserAssertion(bootStrapContext.Token);
AuthenticationContext authContext = new AuthenticationContext(StartUp.adAuthority);
var authResult = authContext.AcquireToken(routerServiceResourceId, uICredentials, userAssertion);
with the exception being raised on the final line. The parameters here are:
StartUp.UiClientId: The application id for the UI in the service directory.
StartUp.UiSecret: The secret key for the UI app in the service directory.
StartUp.adAuthority: I have tried this with the common AD endpoint for multi-tenant applications (https://login.microsoftonline.com/common/) and with the specific endpoint for this tenant (https://login.microsoftonline.com/tenantid). Both give the same result.
routerServiceResourceId: The App Id URI for the data service.
In addition, I have set 'SaveSigninToken' to true in the TokenValidationParameters for the UI application so I can obtain the BootstrapContext.Token.
As far as I can see, this is everything it should need to work but, as I say, I continually get the error above =/
Can anyone suggest a way forward / obvious solution / further reading for this. I seem to be banging my head against this and not getting very far. I am also not 100% what information is pertinent here regarding the problem so if I have missed any important points, please let me know and I can update the question.
The OnBehalf of flow isn't really appropriate in this case. The OnBehalf of flow is appropriate when a WebAPI receives an access token and needs to get an access token for a downstream WebAPI. The flow that is most appropriate in your case is the OpenID Connect code+id_token flow. In this flow the WebApp receives an id_token that authenticates the user and an authorization code that allows the WebApp to get an access token for a back end server. The WebApp then redeems the authorization code for the access token.
The best example of this flow is here:
https://github.com/AzureADSamples/WebApp-WebAPI-OpenIDConnect-DotNet
Pay attention to Startup.Auth.cs where the AuthorizationCodeRecieved notification is set up. This shows how to retrieve the code and redeem it.
I have a Native Client registered in our Azure AD.
When i'm using
var ar = _context.AcquireToken(resource, clientId, returnUri);
It opens the Prompt for Username and Password. If I enter them correctly I get a valid AccessToken and everything is fine.
When I'm now trying to enter the credentials in code, via UserCrendtial:
var credential = new UserCredential("username", "password");
var ar = _context.AcquireToken(resource, clientId, credential);
But both resulting in an Error when I'm trying it with the directly entered Credentials.
AADSTS65001: No permission to access user information is configured
for '4915f024-blah-blah-blah-f580ab5b0487' application, or it is
expired or revoked.
I have tried the normal (string, string) and the (string, SecureString) overload of the UserCredential.
I have tried it with the exact same combination of username & password, which I have entered in the Prompt, of the first overload from AcquireToken.
I have also tried to give the Application in Azure all the Delegated Permissions:
Read directory data
Read and write directory data
Access your organization's directory
And added Windows Azure Service Management API Application with Permission:
Access Azure Service Management
Nothing helped.
As a sidenote, the Application in the Azure has permissions to a SharePoint O365 Tenant. To Read and Write ListItems I don't know if this is relevant. The Resource i'm passing through is the SharePoint Adress.
I don't need any user access over the Graph Api to the Azure. I only need that AccessToken to access our SharePoint Online.
Edit:
Architecture:
Description:
We have a Web Api Project which handles the User Authorization, Load Balancing etc. This Web Api Project, will be queried by either Native Dekstop Clients or Hybrid HTML5 & Javascript Mobile Device Apps.
The Web Api Project needs to Read, Create, Update & Delete Data from our SharePoint O365 Tenant. So this where I need the AccessToken to init a ClientContext or send i via a rest response.
Since the Web Api handles the User authorization, there is an endpoint for users to login already and in this endpoint I want to acquire the Token. That's why I want it to be silent, because the "flexbile browser popup" is already there.
Maybe I don't need in this scenario the Token acquiring with Username / Password, but then I don't know how to configure the Azure App right to work with all the different native client's.
not sure if it's your case but you can use :
built in auth (setting 'on' in webapp options; then create express app or/and then chose advanced mode with same apps ids);
then add AD native client app;
login to old classic portal there select native app and in config add access to you express/advacsed web app;
after that you will able login in browser; and with adal lib will able login to access you api from mobile devices;
for more see ms docs and samples;
The direct use of username and password has important limitations, please make sure you are not stumbling on any of the ones listed in http://www.cloudidentity.com/blog/2014/07/08/using-adal-net-to-authenticate-users-via-usernamepassword/.
Also note, nothing that requires displaying a user consent screen (as all the permissions you described will) or specific disambiguation steps (like trying to use a guest user from X to access a resource protected by tenant Y) will work.
What is your scenario? Any specific reason for which you want to use username/password instead of the more flexible browser popup?