I have two webprojects: MyApp and Api.MyApp. MyApp is an MVC5 Application and Api.MyApp is a MVC WebAPI application.
MyApp is a rich client application that calls the API project for most of its operations. For authorization I am using a Bearer token for the web api but I would also like to have a cookie
so I can secure certain routes in the main MyApp MVC project.
To get the bearer token I call "http://api.myapp/token" can I throw this bearer token into a cookie and have the MVC project recognize it or do I have to send 2 separate calls, 1 to the api to get the bearer token and 1 to the mvc app to get the cookie. This seems a little redundant, is there a better way?
Yes.
Assuming your applications are responding on something like:
api.example.com
www.example.com
The user comes to your site on www.example.com and provides their credentials. Your app then makes an AJAX call to api.example.com to get the token. You have a couple of options now:
api.example.com returns the token, along with a cookie, with the domain set to .example.com
api.example.com returns the token, and the client-side script sets that into a cookie with the domain set to .example.com
If you do this, then both the API and the client application should have access to the cookie based token.
You may have to roll your own authorisation mechanism based on the bearer cookie if you're not using .Net auth tokens.
If however you are on intranet type domains (i.e. http://myapp/ and http://api.myapp) then you'll have to go with option 2 and use the default domain for the cookie (you can't set a cookie with just a single period in the domain otherwise I could set one to ".com" and splurge data everywhere.)
Related
Actors:
Black box (MS Power App custom connector) with user logged in
API A - .NET Standard WebApi with [Authorize] attribute and AAD authorization enabled (no additional verification in code), ida:audience="A" in web.config
API B - .NET Standard WebApi with [Authorize] attribute and AAD authorization enabled (no additional verification in code), ida:audience="B" in web.config
API C - .NET Standard WebApi with [Authorize] attribute and AAD authorization enabled (no additional verification in code), ida:audience="C" in web.config
Flow:
Power App connector calls API A. Within the code of API A (C#) I can decode JWT from Authorization header and see which user is logged in. Now, I have to call API B and API C and then return something to Power App connector. API B and API C must be able to also decode JWT and get UPN from token.
Problem:
When I tried to reuse whole Authorization header (just get it within API A and add to HttpClient to call API B and C) I get 401.
Now I know that was because of ida:Audience value. I suppose it is part of .NET framework verification, beyond my control. When I changed ida:Audience in API B and C to "A" it worked. But it was only for testing purposes, I am not allowed to do it in production.
Then I tried to set scopes in Power App connector to multiple values (delimited by space) with different audiences - no luck, error from AAD, multiple audiences not allowed.
So, my question is: is it possible in my scenario to do what I need? I have only access token for audience A and have to authorize (with impersonation) in endpoints with other audience value.
This is exactly what the on-behalf-of flow is for.
It allows API A to take the access token it received and ask for an access token to API B (with the same user info in the token).
More info on the flow: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow.
Example request content from documentation to token endpoint that uses a client secret:
//line breaks for legibility only
POST /oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com/<tenant>
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
client_id=535fb089-9ff3-47b6-9bfb-4f1264799865
&client_secret=sampleCredentia1s
&assertion=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6InowMzl6ZHNGdWl6cEJmQlZLMVRuMjVRSFlPMCJ9.eyJhdWQiOiIyO{a lot of characters here}
&scope=https://graph.microsoft.com/user.read+offline_access
&requested_token_use=on_behalf_of
Using MSAL.NET is definitely better than using the HTTP endpoint directly though.
You would replace the scope in this request with a scope from API B.
I have set up a Web Application with ASP.NET Razor Pages with -> Individual User Accounts -> Connect to an existing user store in the cloud (Azure AD B2C).
This works really well and I could both sign up and sign in to the web application.
However when I follow the guide for API I don't understand how to sign in.
The example Controller /weatherforecast simply returns a HTTP 401 when the web application is started.
Looking at the file structure I can't find any clues either but this could be similar to scaffolding I guess.
https://stackoverflow.com/a/50677133/3850405
If I comment out [Authorize] from WeatherForecastController I get a HTTP 200 so what I need is probably just a token from Azure AD B2C that is being sent to the Controller in the GET request.
I know that the B2C tenant and application work since I use the same application for the API as I did with the Web Application. It was set up using Microsofts own guide:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-tenant
Update 2020-07-27:
Applications are now Legacy and App registrations should be used instead. See this guide:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-register-applications?tabs=app-reg-ga#register-a-web-application
Old:
Fixed it using these guides:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/tokens-overview
https://learn.microsoft.com/en-us/azure/active-directory-b2c/access-tokens
I had some trouble where I got the error "AADB2C90205: This application does not have sufficient permissions against this web resource to perform the operation. numerous times. Turned out I had not declared the correct scopes for the application.
First step is therefore to make sure you have a read scope for your Azure AD B2C application under Published scopes:
Then under API access add your application with the scope read.
Then perform a GET request with this format, simplest way to test is to use it in Chrome or any other browser:
https://<tenant-name>.b2clogin.com/tfp/<tenant-name>.onmicrosoft.com/<policy-name>/oauth2/v2.0/authorize?
client_id=<application-ID>
&nonce=anyRandomValue
&redirect_uri=https://jwt.ms
&scope=https://<tenant-name>.onmicrosoft.com/api/read
&response_type=code
Make sure the redirect_uri is present as Reply URL for your application.
This should give you a result like after logging in like https://jwt.ms/?code=... or https//localhost:44376/signin-oidc?code= depending on redirect_uri. Microsoft example uses https://jwt.ms but I prefer to keep my codes on domains that I control.
Copy the value from code parameter and then perform a POST request, I use Postman.
POST <tenant-name>.onmicrosoft.com/oauth2/v2.0/token?p=<policy-name> HTTP/1.1
Host: <tenant-name>.b2clogin.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&client_id=<application-ID>
&scope=https://<tenant-name>.onmicrosoft.com/api/read
&code=eyJraWQiOiJjcGltY29yZV8wOTI1MjAxNSIsInZlciI6IjEuMC...
&redirect_uri=https://jwt.ms
&client_secret=<app-key>
client_secret is from Keys:
Correct response should look like this:
Then you can copy the value for access_token and access your local API with Bearer Authorization. To see the content of your access_token you can copy the value to https://jwt.ms/
I have an ASP.NET web application, let's call it Web App A, that is self-hosted using OWIN and NancyFX.
Web App A uses Basic Authentication, which is set up in CustomBootstrapper.cs like this:
pipelines.EnableBasicAuthentication(new BasicAuthenticationConfiguration(
container.Resolve<IUserValidator>(),
"MySpecificRealm"));
After querying the user for the username and password, Web App A calls an authentication REST API to validate the credentials and return a security token if they are valid.
I am being asked to make a subset of that app, let's call this subset Web App B, when a valid security token is specified in the URL instead of prompting for the credentials.
The following picture might help explain this:
Per the usual, there are various modules in Web App A that call:
this.RequiresAuthentication();
How can I bypass the authentication when a valid security token is passed as a parameter in the URL?
You need to either add a parameter to a config file or use a conditional compilation symbol. Either of these will set a flag that you can then check to bypass the wiring up of the Basic Authentication in the pipelines and possibly the this.RequiresAuthentication().
For those Nancy Modules that require authentication, add a required URL parameter to the incoming request for the caller to supply the security token.
You are going to need the REST API to have a call that validates the security token, and you will need to call it and receive back the userName so you can create your IUserIndentity.
I've got all the code working to generate the JWT and I've wired up my ConfigureServices with the proper config code but I'm not seeing the header actually get set.
I assumed that the middleware would do this for you but maybe not, is it up to me to return the token from the login method of my controller and the client to then take it and set the header for subsequent requests?
No it does not.
The way it works is that you send your login credentials to a login server. In most cases its the same but in more secure applications this won't be the case.
The server then authenticates your credentials, creates a JWT token and sends that back to you.
You can then use that JWT in your header when making a request to the application server:
"Authorization":"Bearer xxxxx.yyyyy.zzzzz"
This needs to be done with every call to the server because the point of JWT is that it is stateless, meaning the server does not save the data at all. Instead in reads the JWT token with every call and grants access/functionality based on that.
I'm trying to figure out how to configure/use the Asp.Net Core Authorization with the credentials and user data in another server, accessed through an API.
For example, in the "Auth" server, we have the Auth database, that stores users, roles and claims. Some examples:
GET https://auth.myserver.com/v1/users/4/IsInRole/Admin
The response is a simple bool.
Or:
GET https://auth.myserver.com/v1/users/4/GetRolesForUser/
The response is a list of roles.
The another server is the resource server (also entirely API based, no front-end). It stores a lot of data that demands authorization by roles and claims.
Also, we have a third player: the client.
The client will:
Ask the auth server to get a bearer and a refresh token, using an username and a password
The client stores those tokens and send the bearer to the resource server to get some data
The resource server will ask the auth server if the bearer token is valid
If it is, then the resource server needs to ask the auth server again about the user that has that bearer token, and if that user has the necessary holes/claims that are necessary to access the requested resource.
The 4 step is my doubt. I imagine that should happen on the resource server controllers:
[HttpGet]
[Authorize(Roles = "Admin")] //API CALL HERE TO THE AUTH SERVER (?)
public async Task<IActionResult> GetData()
{
...
Basically, I don't know how to Authenticate an user on the context (just until the request is returned), putting it in the HttpContext.User, using my own custom validation process.
I've tried to simplify this architecture as much as possible to make my question more clear. Please forget about the security on the "Auth" server.
If you are using jwts this flow can be simplified roles can be stored in claims which means that no api call is needed in the authorise attribute.
Also the resource server doesn't need to verify that the token is valid that can be done using a secret.
Look into thinktecture the following are good resources https://leastprivilege.com/ and https://brockallen.com/