Recently I’ve received lot of comments and emails asking how we can decouple the OWIN Authorization Server we’ve built in the previous posts from the resources we are protecting. If you are following the posts mentioned below you will notice that we’ve only one software component (API) which plays both roles: Authorization Server and Resource Server.
There is nothing wrong with the the current implementation because OAuth 2.0 specifications never forces the separation between the Authorization Server and the Resource Server, but in many cases and especially if you have huge resources and huge number of endpoints you want to secure; then it is better from architecture stand point to decouple the servers. So you will end up having a stand alone Authorization Server, and another stand alone Resource Server which contains all protected resources, as well this Resource Server will understand only the access tokens issued from the Authorization Server.
You can check the source code on Github.
- Token Based Authentication using ASP.NET Web API 2, Owin, and Identity – Part 1.
- AngularJS Token Authentication using ASP.NET Web API 2, Owin, and Identity – Part 2.
- Enable OAuth Refresh Tokens in AngularJS App using ASP .NET Web API 2, and Owin – Part 3.
- ASP.NET Web API 2 external logins with Facebook and Google in AngularJS app – Part 4.
- Update Oct-27 New post: better approach to Decouple Authorization Server from Resource Server by using JSON Web Tokens (JWT).
OAuth 2.0 Roles: Authorization Server, Resource Server, Client, and Resource Owner
Before we jump into implementation and how we can decouple the servers I would like to emphasis on OAuth 2.0 roles defined in the specifications; so we’ll have better understanding of the responsibility of each role, by looking at the image below you will notice that there are 4 roles involved:
Resource Owner:
The entity or person (user) that owns the protected Resource.
Resource Server:
The server which hosts the protected resources, this server should be able to accept the access tokens issued by the Authorization Server and respond with the protected resource if the the access token is valid.
Client Applications:
The application or the (software) requesting access to the protected resources on the Resource Server, this client (on some OAuth flows) can request access token on behalf of the Resource Owner.
Authorization Server:
The server which is responsible for managing authorizations and issuing access tokens to the clients after validating the Resource Owner identity.
Note: In our architecture we can have single Authorization Server which is responsible to issue access token which can be consumed by multiple Resource Servers.
Decoupling OAuth 2.0 OWIN Authorization Server from Resource Server
In the previous posts we’ve built the Authorization Server and the Resource Server using a single software component (API), this API can be accessed on (http://ngauthenticationAPI.azurewebsites.net), in this demo I will guide you on how to create new standalone Resource API and host it on different machine other than the Authorization Server machine, then configure the Resource API to accept only access tokens issued from our Authorization Server. This new Resource Server is hosted on Azure can be accessed on (http://ngauthenticationResourcesAPI.azurewebsites.net).
Note: As you noticed from the previous posts we’ve built a protected resource (OrdersController) which can be accessed by issuing HTTP GET to the end point(http://ngauthenticationAPI.azurewebsites.net/api/orders), this end point is considered as a resource and should be moved to the Resource Server we’ll build now, but for the sake of keeping all the posts on this series functioning correctly; I’ll keep this end point in our Authorization Server, so please consider the API we’ve built previously as our standalone Authorization Server even it has a protected resource in it.
Steps to build the Resource Server
In the steps below, we’ll build another Web API which will contain our protected resources, for the sake of keeping it simple, I’ll add only one secured end point named “ProtectedController”, any authorized request to this end point should contain valid bearer token issued from our Authorization Server, so let’s start implementing this:
Step 1: Creating the Resource Web API Project
We need to add new ASP.NET Web application named “AngularJSAuthentication.ResourceServer” to our existing solution named “AngularJSAuthentication”, the selected template for the new project will be “Empty” template with no core dependencies, check the image below:
Step 2: Install the needed NuGet Packages
This project is empty so we need to install the NuGet packages needed to setup our OWIN Resource Server, configure ASP.NET Web API to be hosted within an OWIN server, and configure it to only uses OAuth 2.0 bearer tokens as authorization middle ware; so open NuGet Package Manager Console and install the below packages:
1 2 3 4 5 |
Install-Package Microsoft.AspNet.WebApi -Version 5.2.2 Install-Package Microsoft.AspNet.WebApi.Owin -Version 5.2.2 Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.0.0 Install-Package Microsoft.Owin.Cors -Version 3.0.0 Install-Package Microsoft.Owin.Security.OAuth -Version 2.1.0 |
The usage for each package has been covered on the previews posts, feel free to check this post to know the rational of using each package is used for.
Important note: In the initial post I was using package “Microsoft.Owin.Security.OAuth” version “3.0.0” which differs from the version used in the Authorization Server version “2.1.0”, there was a bug in my solution when I was using 2 different versions, basically the bug happens when we send an expired token to the Resource Server, the result for this that Resource Server accepts this token even if it is expired. I’ve noticed that the properties for the Authentication ticket are null and there is no expiry date. To fix this issue we need to unify the assembly version “Microsoft.Owin.Security.OAuth” between the Authorization Server and the Resource Server, I believe there is breaking changes between those 2 versions that’s why ticket properties are not de-crypted and de-serialized correctly. Thanks for Ashish Verma for notifying me about this.
Step 3: Add OWIN “Startup” Class
Now we want to add new class named “Startup”. It will contain the code below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
[assembly: OwinStartup(typeof(AngularJSAuthentication.ResourceServer.Startup))] namespace AngularJSAuthentication.ResourceServer { public class Startup { public void Configuration(IAppBuilder app) { HttpConfiguration config = new HttpConfiguration(); ConfigureOAuth(app); WebApiConfig.Register(config); app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); app.UseWebApi(config); } private void ConfigureOAuth(IAppBuilder app) { //Token Consumption app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions { }); } } } |
As we’ve covered in previous posts, this class will be fired once our Resource Server starts, as you noticed I’ve enabled CORS so this resource server can accept XHR requests coming from any origin.
What worth noting here is the implementation for method “ConfigureOAuth”, inside this method we are configuring the Resource Server to accept (consume only) tokens with bearer scheme, if you forget this one; then your Resource Server won’t understand the bearer tokens sent to it.
Step 3: Add “WebApiConfig” Class
As usual we need to add the WebApiConfig class under folder “App_Start” which contains the code below:
1 2 3 4 5 6 7 8 9 10 11 |
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API routes config.MapHttpAttributeRoutes(); var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First(); jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); } } |
This class is responsible to enable routing attributes on our controller.
Step 4: Add new protected (secured) controller
Now we want to add a controller which will serve as our protected resource, this controller will return list of claims for the authorized user, those claims for sure are encoded within the access token we’ve obtained from the Authorization Server. So add new controller named “ProtectedController” under “Controllers” folder and paste the code below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[Authorize] [RoutePrefix("api/protected")] public class ProtectedController : ApiController { [Route("")] public IEnumerable<object> Get() { var identity = User.Identity as ClaimsIdentity; return identity.Claims.Select(c => new { Type = c.Type, Value = c.Value }); } } |
Notice how we attribute the controller with [Authorize] attribute which will protect this resource and only will allow HTTP GET requests containing a valid bearer access token sent in the authorization header to pass, in more details when the request is received the OAuth bearer authentication middle ware will perform the following:
- Extracting the access token which is sent in the “Authorization header” with the “Bearer” scheme.
- Extracting the authentication ticket from access token, this ticket will contain claims identity and any additional authentication properties.
- Checking the validity period of the authentication ticket.
Step 5: Hosting the Authorization Server and Resource Server on different machines
Until this step and if you are developing locally on your dev machine, if you tried to obtain an access token from your Authorization Server i.e. (http://AuthServer/token) and then send this access token to the secured end point in our Resource Server i.e. (http://ResServer/api/protected) the result for this request will pass and you will have access to the protected resource, how is this happening?
One your dev machine once you request an access token from your Authorization Server; the OAuth middleware will use the default data protection provider in your Authorization Server, so it will use the “validationKey” value in machineKey node stored in machine.config file to issue the access token and protect it. The same case applies when you send the access token to your Resource Server, it will use the same machineKey to decrypt the access token and extract the authentication ticket from it.
The same applies if you are planing on your production environment to host your Authorization Server and your Resource Server on the same machine.
But in our case I’m hosting my Authorization Server on Azure website using West-US region, and my Resource Server is hosted on Azure websites on East-US region so both are totally on different machines and they share different machine.config files. For sure I can’t change anything on machine.config file because it is used by different sites on the Azure VMs I’m hosting my APIs on it.
So to solve this case we need to override the machineKey node for both APIs (Authorization Server and Resource Server) and share the same machineKey between both web.config files.
To do so we need to generate a new machineKey using this online tool, the result after using the tool will be as the below: As advised by Barry Dorrans it is not recommend to use an online tool to generate your machineKey because you do not know if this online tool will store the value for your machineKey in some secret database, it is better to generate the machineKey by your self.
To do so I’ll follow the steps mentioned in article KB 2915218, Appendix A which uses Power Shell commands to generate machineKey, so after you open Power Shell and run the right command as the image below you will receive new machineKey
1 |
<machineKey validationKey="A970D0E3C36AA17C43C5DB225C778B3392BAED4D7089C6AAF76E3D4243E64FD797BD17611868E85D2E4E1C8B6F1FB684B0C8DBA0C39E20284B7FCA73E0927B20" decryptionKey="88274072DD5AC1FB6CED8281B34CDC6E79DD7223243A527D46C09CF6CA58DB68" validation="SHA1" decryption="AES" /> |
Note: Do not use those for production and generate a new machineKey for your Servers using Power Shell.
After you generate it open the web.config file for both the Authorization Server (AngularJSAuthentication.API project) and for the Resource Server (AngularJSAuthentication.ResourceServer) and paste the machineKey node inside the <system.web> node as the below:
1 2 3 4 5 6 7 8 |
<system.web> <compilation debug="true" targetFramework="4.5" /> <httpRuntime targetFramework="4.5" /> <machineKey validationKey="VALUE GOES HERE" decryptionKey="VALUE GOES HERE" validation="SHA1" decryption="AES"/> </system.web> |
By doing this we’ve unified the machineKey for both Authorization Server and Resource Server (Only this API in case of Azure shared hosting or any other shared host) and we are ready now to test our implementation.
Step 6: Testing the Authorization Server and Resource Server
Now we need to obtain an access token from our Authorization Server as we did before in the previous posts, so we can issue HTTP POST to the end point (http://ngauthenticationapi.azurewebsites.net/token) including the resource owner username and password as the image below:
If the request succeeded we’ll receive an access token, then we’ll use this access token to send HTTP GET request to our new Resource Server using the protected end point (http://ngauthenticationresourcesapi.azurewebsites.net/api/protected), for sure we need to send the access token in the Authorization header using bearer scheme, the request will be as the image below:
As you notice we’re now able to access the protected resource in our new Resource Server and the claims for this identity which obtained from the Authorization Server are extracted.
That’s it for now folks, hopefully this short walk through helped in understanding how we can decouple the Authorization Server from the Resource Server.
If you have any comment or question please drop me a comment
You can use the following link to check the demo application.
You can use the following link to test the Authorization Server (http://ngauthenticationAPI.azurewebsites.net),
You can use the following link to test the Resource Server (http://ngauthenticationResourcesAPI.azurewebsites.net)
You can check the source code on Github.
Can you use the credentials or access token retrieved from this authorization server with that of Azure Mobile App (.Net Backend) during authentication?
I tried implement oauth security. Oauth provider and consumer webApi webservice are in different ports like different machine. If i implement this case on iis service, authorization is provided.
But Oauth provider on IIS and Consumer Web API on windows service authorization is not runned. How can i implement it on windows service?
I think that windows service is not use machine key.
Hello Taseer,
Thanks for the post, we are thinking to implement the Authorization & Resource servers as separate SELF-HOSTED Restful Web API (i.e. hosted in window service not IIS) via OWIN/Katana. would this approach work? Thanks in advance.
Hi, thanks for the great article.
But i still have a question:
First i go to the Authorization Server (ie. http://localhost:49493) ask in /api/audience for my clientID.
I get the Client_ID and a base64Secret.
With the Client_ID is ask for a Token on /oauth2/token, then i get my access_token.
When i send this token to the Ressource Server (i.e. http://localhost:56248) it should verify it, but i does not accept my token.
When i copy it to jwt.io it says “Invalid signature”. When i copy the base64secret to the “secret” field its valied. Do i have to send the secret to the endpoint so it can verify the token and when, how?
Hi thanks so much for the tutorial it’s really helpful.
Please is it advisable to use the same database for Auth server and resource servers ?
thanks in advance
Hello,
Usually, you need to separate your Authentication/Authorization data from your business data so you can reuse this easier. You can take a look on ThinkTecture Identity Server DB design to have a better understanding of DB structure.
Hi Taiseer,
This is a really helpful tutorial and a much better use-case. Thank you so much.
However, one thing I couldn’t figure out is that how resource server knows about the authorization server endpoint it needs to hit to authorize user before providing the protected resource.
I know this is a really stupid question but I might as well ask now than be ashamed later.
Thanks for the post again.
Hi Aman,
Not necessarily the RS needs to know the AS. It is usually supposed that a Client app is in the middle of the process. The Client app knows both the resource Url (RS) and the AS. When the RS answers with an unauthorized response, the Client app redirects the user to the AS login page. After successful logon, the AS usually calls a callback on the RS. This callback puts the user on the authorized track of the RS.
Given this flow, is the AS who knows the RS and not the otherwise. But I guess you can expect variations of this flow.
Kr
I had the same confusion earlier, but it looks like the token itself contains all required data, and you don’t need the issuer again to verify. so, the bearer will issue the token, and once you send the token to the resource server, resource server will not confirm it with oauth provider. instead, it will be interpreted inside resource server only.
if you want you can test the following:
1- create the provider application, and run it.
2- using fiddler or any client, call the api/token and save the token.
3- turn off the provider application totally.
4-create the resource application as mentioned in this topic above, and run it.
5- using fiddler or any client, call the api/values, and make sure you include the token in header as required.
6- resource will reply to you successfully, even provider is not accessible.
I cannot provide the full details because of lack of some details, but this is the case, and I already test it.
Summary: Provide is to issue token, not to verify them. resource will verify and act accordingly.
Hi, similar question to @Aman Shankhdhar, I’ve implemented the above steps but my Resource API doesn’t recognize my Auth Tokens from auth/token, it only works if I pass tokens from resource/token. (Instead of creating a resource server in this tutorial I created a auth server for my resource)
Does the resource have to be within the namespace of the authentication? AngularJSAuthentication.ResourceServer.App_Start
or can I have them completely separate?
Indeed a wonderful article that I was looking for decoupling servers. I am a follower of your articles and find the information precise and concise.
Hi Taiseer,
Great series about OWIN/Katana OAuth! Clear and useful 🙂
I succesfully implemented everything in one evening.
Now I am searching for article or/and example which will help me with combintaion of Ouath and OpenId.
Do you have some tips, snippets?
I found that implemented in java WSO2 (https://docs.wso2.com/display/IS510/WSO2+Identity+Server+Documentation) gives such combination of both protocols but I cannot find something useful in .NET.
Best regards and thank you for your work 🙂
Taiseer, have you any experience with how to handle the absence of the MachineKey in .NET Core 2.0? I’ve been scouring the web for some insight and can’t quite get a handle on it yet. I am poking arounf with the DataProtection API but as yet have not gotten adequate understanding of how to handle this requirement in Core 2.0.
You are brilliant. Thank you for this.
How does Bearer Token Expiration work with this setup? Do they ever expire?
Can you help me
I have 3 more project asp mvc and diference database
every project with login and in controller any difference role.
help me..
I want to make all projetc in one login with external login (no google or facebook), custom login with another database.
can you send me two (2) sample projects. project one for recieve external login and another project send login.
your project in one, so it makes me not understand. and your projects no build.
please help me..
I want server Resource Server redirect Login page if it’s not authorize, how i can build it
I had check authorize in controller proctected but if i have multi resources i will check multi controller.
You can help me, give solution to resolve it ?
Hi Taiseer,
Your article has helped me a lot. I really appreciate your effort in writing this detailed article. Thank you verymuch!
The code works verywell on my local computer. When I deploy it on the hosting environment I get a 403 forbidden error when I try to generate a token. What could I be missing? Can you please help me with this?
Thanks
Rakesh
Hello Taiseeer,
Tons of thanks for this very helpful tutorial !
I am trying to send different views based on user authorization. I’ve created successfully auth and resource server. Now to create another asp.net mvc app, i want to use authorize attribute and check if user is authenticated. So that i can send different view based on request.
Your guidance will be of very help. Thanks in advance..
Please note that i am using auth server and resource server to serve this asp.net mvc app, whose action will cater required Views based on request received.
Hi Taisser,
Thanks for this good tutorial.
I have some needs and questions.
Is resource and authorization server using a different database regardless where the database server is?
In my app, I need to get a list of (certain) users. If these server using the same database I could just retrieve it.
If they are using different database, how do I get them the list of users?
Should I make an API di authorization server to provide the list?
And then, how to retrieve it, should I still wrap it in another API in resource server or should I just call it in my app?
And last question is a bit similar to what Jerry Ferrel asked above, it is about not using machine key.
If I want the authorization server to act like external server, how to do it? Can you provide another tutorial about how to achieve it?
Can you or someone help me, especially about how to retrieve users if it on different database?
Thanks
Suwandy
Hi TAISEER,
Thanks for your excellent code. I have a question . Whenever I put the autorisation attribute -it alwasy throws an authorisation error
{
“Message”: “Authorization has been denied for this request.”
}
[Authorize(Roles = “Admin”)]
public async Task RegisterAdmin(AdminRegistrationModel adminModel)
I have checked the token the role ‘Admin is there. What changes needs to be made
Hi Sir,
Excellent article, with detail.
My questions: is
When the client request to Resource Server, in the above sample Resource server itself validating token.
In my case, when the client request to Resource Server, it has to contact Authorization server to validate token
and then the Resource server will return the result to Client.
Can you explain me how to achieve this?
Do you have any sample for this scenario?
Thanks in Advance!
thank you too much.
this is the best sample of Decouple OWIN Authorization Server from Resource Server.
i Am very happy using this clear sample.
i suggest all developer to attention this tutorial.
:).
Thanks a lot for this wonderful tutorial Taiser. Much appreciated.
I am trying to use Oauth for a multi-tenant system. (One Auth Server, Multiple Resource Servers). Is there a way I can avoid keeping the same Machine Key on all resource servers?
Something like a Dynamic Machine Key, which can be used at runtime?
Can we make it as mixed mode authentication (Windows and form)?
I have implemented my Auth server from the code in this series. Great stuff by the way most detailed explanation of Owin Oauth I could find.
I have run into an issue that I can’t work out how to resolve. When multiple calls try and renew the auth token using the refresh token at the same time. The first one updates everything then the second fails because the refresh token that it has is now out of date. Any Ideas how to resolve this?
I might be being a bit silly… but;
would it be possible to do this with an IdentityServer authority. So if we have an net framework Owin self hosted WebApi that wants to be protected by that identity server – am I barking up the wrong tree? (maybe there are packages to handle this scenario? – I’m used to working in .Net Core these days and I’m not really used to working in a net framework owin project).
It sounds like it should be possible – but I’m a little unsure about this machine key stuff (I think Identity server exposes a public key for this purpose and for the packages that I’m familiar with using in .net core, it’s all taken care of for me! – same with api audiences – so those claims that are handled under the hood – such that I don’t need to check if the given token (which is otherwise valid) actually allows access to this particular API).
Does any of that question make sense 🙂 ?