AngularJS Token Authentication using ASP.NET Web API 2, Owin, and Identity

This is the second part of AngularJS Token Authentication using  ASP.NET Web API 2 and Owin middleware, you can find the first part using the link below:


You can check the demo application on (http://ngAuthenticationWeb.azurewebsites.net), play with the back-end API for learning purposes (http://ngauthenticationapi.azurewebsites.net), and check the source code on Github.

AngularJS Authentication

In this post we’ll build sample SPA using AngularJS, this application will allow the users to do the following:

  • Register in our system by providing username and password.
  • Secure certain views from viewing by authenticated users (Anonymous users).
  • Allow registered users to log-in and keep them logged in for 24 hours 30 minutes because we are using refresh tokens or until they log-out from the system, this should be done using tokens.

If you are new to AngularJS, you can check my other tutorial which provides step by step instructions on how to build SPA using AngularJS, it is important to understand the fundamentals aspects of AngularJS before start working with it, in this tutorial I’ll assume that reader have basic understanding of how AngularJS works.

Step 1: Download Third Party Libraries

To get started we need to download all libraries needed in our application:

  • AngularJS: We’ll serve AngularJS from from CDN, the version is 1.2.16
  • Loading Bar: We’ll use the loading bar as UI indication for every XHR request the application will made, to get this plugin we need to download it from here.
  • UI Bootstrap theme: to style our application, we need to download a free bootstrap ready made theme from http://bootswatch.com/ I’ve used a theme named “Yeti”.

Step 2: Organize Project Structure

You can use your favorite IDE to build the web application, the app is completely decoupled from the back-end API, there is no dependency on any server side technology here, in my case I’m using Visual Studio 2013 so add new project named “AngularJSAuthentication.Web” to the solution we created in the previous post, the template for this project is “Empty” without any core dependencies checked.

After you add the project you can organize your project structure as the image below, I prefer to contain all the AngularJS application and resources files we’ll create in folder named “app”.

AngularJS Project Structure

Step 3: Add the Shell Page (index.html)

Now we’ll add the “Single Page” which is a container for our application, it will contain the navigation menu and AngularJS directive for rendering different application views “pages”. After you add the “index.html” page to project root we need to reference the 3rd party JavaScript and CSS files needed as the below:

Step 4: “Booting up” our Application and Configure Routes

We’ll add file named “app.js” in the root of folder “app”, this file is responsible to create modules in applications, in our case we’ll have a single module called “AngularAuthApp”, we can consider the module as a collection of services, directives, filters which is used in the application. Each module has configuration block where it gets applied to the application during the bootstrap process.

As well we need to define and map the views with the controllers so open “app.js” file and paste the code below:

So far we’ve defined and mapped 4 views to their corresponding controllers as the below:

Orders View

Step 5: Add AngularJS Authentication Service (Factory)

This AngularJS service will be responsible for signing up new users, log-in/log-out registered users, and store the generated token in client local storage so this token can be sent with each request to access secure resources on the back-end API, the code for AuthService will be as the below:

Now by looking on the method “_saveRegistration” you will notice that we are issuing HTTP Post to the end point “http://ngauthenticationapi.azurewebsites.net/api/account/register” defined in the previous post, this method returns a promise which will be resolved in the controller.

The function “_login” is responsible to send HTTP Post request to the endpoint “http://ngauthenticationapi.azurewebsites.net/token”, this endpoint will validate the credentials passed and if they are valid it will return an “access_token”. We have to store this token into persistence medium on the client so for any subsequent requests for secured resources we’ve to read this token value and send it in the “Authorization” header with the HTTP request.

Notice that we have configured the POST request for this endpoint to use “application/x-www-form-urlencoded” as its Content-Type and sent the data as string not JSON object.

The best way to store this token is to use AngularJS module named “angular-local-storage” which gives access to the browsers local storage with cookie fallback if you are using old browser, so I will depend on this module to store the token and the logged in username in key named “authorizationData”. We will use this key in different places in our app to read the token value from it.

As well we’ll add object named “authentication” which will store two values (isAuth, and username). This object will be used to change the layout for our index page.

Step 6: Add the Signup Controller and its View

The view for the signup is simple so open file named “signup.html” and add it under folders “views” open the file and paste the HTML below:

Now we need to add controller named “signupController.js” under folder “controllers”, this controller is simple and will contain the business logic needed to register new users and call the “saveRegistration” method we’ve created in “authService” service, so open the file and paste the code below:

Step 6: Add the log-in Controller and its View

The view for the log-in is simple so open file named “login.html” and add it under folders “views” open the file and paste the HTML below:

Now we need to add controller named “loginController.js” under folder “controllers”, this controller will be responsible to redirect authenticated users only to the orders view, if you tried to request the orders view as anonymous user, you will be redirected to log-in view. We’ll see in the next steps how we’ll implement the redirection for anonymous users to the log-in view once users request a secure view.

Now open the “loginController.js” file and paste the code below:

Step 7: Add AngularJS Orders Service (Factory)

This service will be responsible to issue HTTP GET request to the end point “http://ngauthenticationapi.azurewebsites.net/api/orders” we’ve defined in the previous post, if you recall we added “Authorize” attribute to indicate that this method is secured and should be called by authenticated users, if you try to call the end point directly you will receive HTTP status code 401 Unauthorized.

So add new file named “ordersService.js” under folder “services” and paste the code below:

By looking at the code above you’ll notice that we are not setting the “Authorization” header and passing the bearer token we stored in the local storage earlier in this service, so we’ll receive 401 response always! Also we are not checking if the response is rejected with status code 401 so we redirect the user to the log-in page.

There is nothing prevent us from reading the stored token from the local storage and checking if the response is rejected inside this service, but what if we have another services that needs to pass the bearer token along with each request? We’ll end up replicating this code for each service.

To solve this issue we need to find a centralized place so we add this code once so all other services interested in sending bearer token can benefit from it, to do so we need to use “AngualrJS Interceptor“.

Step 8: Add AngularJS Interceptor (Factory)

Interceptor is regular service (factory) which allow us to capture every XHR request and manipulate it before sending it to the back-end API or after receiving the response from the API, in our case we are interested to capture each request before sending it so we can set the bearer token, as well we are interested in checking if the response from back-end API contains errors which means we need to check the error code returned so if its 401 then we redirect the user to the log-in page.

To do so add new file named “authInterceptorService.js” under “services” folder and paste the code below:

By looking at the code above, the method “_request” will be fired before $http sends the request to the back-end API, so this is the right place to read the token from local storage and set it into “Authorization” header with each request. Note that I’m checking if the local storage object is nothing so in this case this means the user is anonymous and there is no need to set the token with each XHR request.

Now the method “_responseError” will be hit after the we receive a response from the Back-end API and only if there is failure status returned. So we need to check the status code, in case it was 401 we’ll redirect the user to the log-in page where he’ll be able to authenticate again.

Now we need to push this interceptor to the interceptors array, so open file “app.js” and add the below code snippet:

By doing this there is no need to setup extra code for setting up tokens or checking the status code, any AngularJS service executes XHR requests will use this interceptor. Note: this will work if you are using AngularJS service $http or $resource.

Step 9: Add the Index Controller

Now we’ll add the Index controller which will be responsible to change the layout for home page i.e (Display Welcome {Logged In Username}, Show My Orders Tab), as well we’ll add log-out functionality on it as the image below.

Index Bar

Taking in consideration that there is no straight way to log-out the user when we use token based approach, the work around we can do here is to remove the local storage key “authorizationData” and set some variables to their initial state.

So add a file named “indexController.js”  under folder “controllers” and paste the code below:

Step 10: Add the Home Controller and its View

This is last controller and view we’ll add to complete the app, it is simple view and empty controller which is used to display two boxes for log-in and signup as the image below:

Home View

So add new file named “homeController.js” under the “controllers” folder and paste the code below:

As well add new file named “home.html” under “views” folder and paste the code below:

By now we should have SPA which uses the token based approach to authenticate users.

One side note before closing: The redirection for anonymous users to log-in page is done on client side code; so any malicious user can tamper with this. It is very important to secure all back-end APIs as we implemented on this tutorial and not to depend on client side code only.

That’s it for now! Hopefully this two posts will be beneficial for folks looking to use token based authentication along with ASP.NET Web API 2 and Owin middleware.

I would like to hear your feedback and comments if there is a better way to implement this especially redirection users to log-in page when the are anonymous.

You can check the demo application on (http://ngAuthenticationWeb.azurewebsites.net), play with the back-end API for learning purposes (http://ngauthenticationapi.azurewebsites.net), and check the source code on Github.

Follow me on Twitter @tjoudeh

Comments

  1. says

    Maybe it is just me, but app took like 10sec to register at the first time…? after that it worked fine. However, this looks interesting, I haven’t used angular before but it would be cool to try out these things. I actually used token based auth earlier with my multiplayer html5 game, but it was made using against express server (nodejs) and jsonwebtoken. What do you consider as good backend for single page applications? Other than ASP? :)

    • says

      Thanks Mauno for your feedback.
      Well I usually use ASP.NET Web API as a back-end for building APIs, but you have tried on the best back-end servers nowadays, the MEAN stack (MongoDB, Express, AngularJS, and Node) is very popular now when you build SPAs as you can share some JS code between your client and server. Good luck in using AngularJS, one of the best front-end frameworks!

  2. Jonathan says

    Great stuff, thanks for sharing. I’m working on an Web API 2 implementation that requires Network Load Balancing, and I’m trying to figure out how to get it done properly. The main problem I have is this: We can have “N” instances of the web api (let’s say 15 for example) in the farm. So, if a client generates an authentication token and its valid for server 1, how do I make sure it also works for the other servers in the farm? Or, is there a way to move the token generator/validator to an external URL instead of ” TokenEndpointPath = new PathString(“/token”) ” so it can be accessed from all the different instance of the Web API?

  3. says

    @Mauno — I think the initial delay may have been caused by entity framework having had to initially build the database as this was indeed a ‘code first’ implementation… otherwise, it should have been very fast.

    @Jonathan — I’m not sure if the token is stored in the db automatically for retrieval by multiple instances…. however if it is not, then perhaps adding in code to save the token into something like Redis or SQL Server (accessed by many instances in the farm) prior to issuing the token to the client would work.

  4. says

    Great article! Very helpful for me, since I’m just getting started with ASP.NET.

    Just a (probably stupid) question, since I’m not familiar with how azure websites work:

    You have a decoupled WebAPI and AngularJS app implementation, which is really nice. But where did you implement the serving of the shell page (index.html)? There should be a route for that somewhere, right? I don’t know if I accidentally skipped it or what, but I didn’t find it in the tutorial.

    • says

      Hello Simone,
      Glad that the article was beneficial for you.
      Well the “Index.html” is not a partial view, it is the only full html page in the app.
      It is get served by default without typing “index.html” explicitly because in Azure website there is setting called “default documents”. Because it is named “index.html” its getting serviced directly. It will be the same case if it is named “default.aspx” or “default.htm”..etc If it was named something else like mypage.html then I should handle this explicit to service it by default.
      Hope this answers your question.

  5. Bogdan says

    Is there an easy way to enable TwoFactorAuthentication(Email) on your example ? I spent the whole day trying to figure it out but it seems I just don’t get any closer. Thanks a lot!

  6. says

    Hit F5 … so far so good…
    Then registered a new username with password and confirmation keeping my fingers crossed waiting a few seconds for database data to generate…
    Entered my new created username and password on login form and then…Yeeeeeeeeeeeeeeees!!!!,
    Everything works like a charm… Now that’s what I’m talking about!

    I must say I loved your “Nuget bottom-up” stepped approach dealing with Web API 2 OWIN. That’s pretty clean and concise.

    Decoupling Web API 2 OWIN services on back-end and AngularJS app implementation on client in two separate independent apps is the way I see things. 110% with you on that approach. Good job.

    • says

      Thanks mawashikid for your sweet comment :) appreciate it.
      Decoupling the front-end from the back-end is the right way to build SPA, really you can switch to any back-end in future.

  7. Paul says

    Hi Taiseer,

    Excellent article. Thank you.

    The VS2013 ASP.NET MVC project template comes with an AccountController that implements the creation of Roles and UserRoles, so do you have an example of how to implement this in your spa solution?

    Any help appreciated.

    Regards,

    Paul

  8. says

    Hi Taiseer,

    Appreciate your efforts in creating and posting this article as well as source to GitHub.
    Mixing latest and the greatest of angularjs, owin, etc, job well done!

    Thanks a ton! :)

    Cheers,
    –Kaush.

  9. says

    Excellent read. Thank you for detailed explanations.

    I tried commenting out the UseCors line and not sending the Access-Control-Allow-Origin header and my solution still worked. I suppose It’s because both client and server are on same host. Although ports are different. Should fail.

  10. djikay says

    Hi Taiseer,

    Excellent tutorial, thank you for sharing.

    I was wondering if there is a way to use your solution to connect to a “custom” database. At work, we have a custom-made Users table in our SQL Server database that stores usernames, password hashes, etc. but it was created years ago without any consideration for OAuth, Identity, etc. Perhaps some way to intercept the calls to the Identity database and change them to target a differently structured database?

    I’d appreciate your thoughts.

    • says

      Hello djikay,
      Glad it was beneficial for a solution you are working on :) well it is pretty simple to implement this, you do not need to use ASP.NET Identity to implement generating/consuming tokens, in step 10 from the first part of this tutorial you can replace this LOC IdentityUser user = await _repo.FindUser(context.UserName, context.Password); with your custom logic to verify credentials and everything will remain the same, hope this answers your question.

      • djikay says

        Many thanks for the quick response, Taiseer. As I’m very new with this technology and methodology in general, I wasn’t able to actually implement what you said or even use your solution. I’ve downloaded your code from GitHub but it doesn’t run locally (I get an IIS Express error page), probably because it’s trying to connect to your database instance instead of my own, and I’ve no idea what to do to fix this. I’m really confused about all this, but it’s entirely down to my own limitations and not your code. For my particular requirements, I can’t use IIS (I’m self-hosting using OWIN) and I have installed my own copy of SQL Express 2012, so my development environment is different from your article. Anyway, once again, thank you for a wonderful article and hope one day to be able to understand and use it.

  11. says

    Thank you for this, it really helped me understand and implement token based authentication. If you’re adding features, I vote for role based access control. I’ve been having trouble restricting access to specific pages or elements based on the user’s role. My scenario will have the user’s roles returned by the server in the form of a number 1-6, but I’d love to see you cover this topic in any form.

    Thank you!
    Justin

    • says

      Hi Justin,
      Glad it was beneficial for you, the next part will cover roles, this has been requested by many readers. I’m working on it and hopefully it will be published soon.

      • simoco says

        Hi, Taiseer! Thanks for your awesome articles! Have you published something about using roles? Thanks again for you response

      • says

        I also interest in Roles too. But I think it will take time to write it. Below is my idea for further working with Roles in Web Api:
        - Work with Claims-based identity
        - Write a custome Authorization Filter.

        How do you think about this approach, Taiseer?

    • says

      Hi Alex,
      I’m really sorry but I do not have solid hands on experience with backbone, but I believe it is really easy to transfer it. Why not to fork my project and once you applied this using Backbone I’ll update my post to point to your repo.

      • Rodrigo says

        is more a question
        is not regarding their application

        I want to separate module in my application

        app
        controllers
        views
        policies
        services
        - modules
        —- main
        ——– controllers
        ——– views
        ——– service
        ——– index. html
        —- financial
        ——– controllers
        ——– views
        ——– service
        ——– index. html
        app.js

        And only can to have a file of routes, these routes must come from the api for user permission

        I like your example of authentication,I will implement something in my app

        But my question is how to create dynamic routes for module after logging

        you can give me a help to go study and search?

  12. Maxwell says

    Hi Taiseer Joudeh
    Thanks for the material helped me a lot

    I have a question

    I see that is in the memory the user token through clains

    I’m developing a multitenancy, recognize my schema for subdomains, but I can leave in memory my schema without need to always check?

  13. Jose L. Garcia says

    Hi Taiseer, I’m having a problem with register method.
    I don’t know why, the saveRegistration method in authService factory is always sending a post request with a Content-Type text/plain header and the request fails. I’ve tried to force including headers in the $http.post but angularjs always send the post as text/plain.
    Any idea about what could be the problem?

    • says

      Hi Jose, can you make sure it is Post request or a preflighted request (Options) request which issued by the browser to check if your origin is allowed send post request to this API? If its preflighted request make sure that your API supports CORS correctly.

  14. says

    Excellent series! Everything seems to work out great – with one exception. I’m seeing that when I attempt to log in, the browser is sending a “preflight” OPTIONS request before it calls the “~/token” url. This results in a 400 Bad Request, where the payload says {“error”:”unsupported_grant_type”}. How do we work around the browsers preflight request for CORS requests?

      • says

        I guess I should have prefaced my previous comment. Everything seems to work fine except for one thing, which is probably easily fixable: If I log in successfully, then manually navigate back to “/login” (via the address bar) and enter my credentials again, the browser sends a preflight request instead. It fails with a 400 sending back “{“error”:”unsupported_grant_type”}”. The code then goes through the failed path, in which “logout” is called. Then if you go to log in again, the request goes through fine. This is because we’re not adding the “Authorization” header in that request (since we don’t have the token anymore because we just logged out). Would the solution to the problem be in the loginController when “login” is called to first check if the user is logged in. If they are, then skip calling the authService.login() function..? Or, if the user navigates to “/login” but they’re already logged in, we navigate them to somewhere else?

        • says

          Hi Todd,
          You are correct I was able to reproduce this issue, well I think it is better to redirect the logged in user to the /home view if the are logged in.
          I will check why it is returning bad request when the user is logged in, most probably because am sitting the authorization header as you suggested.

          • says

            Another alternative that I think feels better, is to just call Logout right before the Login service call is invoked. That way, there’s no need to do any special-case redirection. Thoughts?

  15. Steve Dickinson says

    Hi,

    I’ve been looking for a way to do authentication with web api and angualrjs for a while and i came across this article, which is not only excellent and well explained, but has help out out with a project i’m working on.

    I have stumbled across an issue and unfortunately its with our friend CORS and wondered if you have seen this happen before.

    First time round on authenticating it hits:

    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
    context.Validated();
    }

    but that is as far as it goes before returning: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource.

    on second time it hits both:

    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
    context.Validated();
    }

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
    context.OwinContext.Response.Headers.Add(“Access-Control-Allow-Origin”, new[] { “*” });

    using (var authRepository = new AuthRepository())
    {
    IdentityUser user = await authRepository.FindUser(context.UserName, context.Password);

    if (user == null)
    {
    context.SetError(“invalid_grant”, “The user name or password is incorrect.”);
    return;
    }
    }

    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
    identity.AddClaim(new Claim(“sub”, context.UserName));
    identity.AddClaim(new Claim(“role”, “user”));

    context.Validated(identity);

    }

    and in it goes and everything works.

    I’ve lost a couple of hours looking into what it could be and have come up against a brick wall.

    Thank you

    • says

      Hi Steve, thanks for your sweet comment, glad I was able to help.
      Could you please check “Todd Behunin” comment thread on this post. Most probably you are trying to login again while you are already logged in. Most probably there is bug in the JS code. Can you please confirm if this is the same issue?

      • Steve Dickinson says

        Bang!! exactly the same issue as “Todd Behunin” was having. I can’t believe I missed it. I used exactly what Todd suggested “just call Logout right before the Login service call is invoked” and it worked and why wouldn’t it and its so simple. Think you get to a stage when the banging of a head on the desk clouds simple thinking.

        Thank you Taiseer and thank you Todd!!

        Taiseer keep up the good work :)

  16. Manish says

    Hi Taiseer,
    Thanks for great article.

    I am stuck in one problem. I have one MVC app in which i want to use token based authentication. In this app i am using web api for all database communication. I am also generating access token on webapi with the help of your article. This part is working fine. Now in application part, when user login first time i am generating acces token and store that in cookies. My question is what should i do here for authentication. for now i am using form authentication by using that i am showing user is authenticated. can you clear me on this. how app flow should be once you get the access token and on which global event i have to work on.

    Thanks

    • says

      Hello Manish,
      If I understood your correctly, In my case where I’m using AngularJS as front end app, I’m storing flag named “IsAuth” along with the access token I’v received on HTML5 local storage. Based on this flag I control UI elements only so I can show/hide links tabc etc…So I believe you need to do this manually too in your MVC app. One question here: Your MVC app and Web API are living on same project? If this is the case then User.IsAuthenticated property should be set and you can control UI elements. Hope this answers your question.

    • says

      You can return the role value along with the “/token” response and you’ll have it in your front end app. You might need it to control UI elements only but do not depend on this value for doing any kind of authorization on the JS application; anyone can tamper with this value using developer tools.

      • marco says

        i saw in your example you doing this but the token is encoded and so i don’t see how you can extract the role from the token?

        • says

          Hi Marco,
          I meant to return it in the response not in the token it self, so it will be on the same level as fields (expires_in, userName, token_type, etc..) if you couldn’t do it let me know and will prepare gist for you showing this.

  17. Mario Di Vece says

    Thanks for this awesome set of articles! I am yet to discover how to set the encryption keys, encrytpion algorithm and signature algorithm for bearer tokens manually. Seems like the only option is by setting the machinekey node in the web.config file. The idea is to be able to read these settings from a custom location in order to be able to deploy multiple instances of the same application. Any chance you know how to do this? I have searched everywhere and no luck. Thanks in advance for your help.

    • says

      Hi Mario, glad you liked the series.
      Well if you have control on your web farm; then I’ll unify the encryption/decryption keys on machine.config level not web.config.
      You can try to use middle-ware “Microsoft.Owin.Security.Jwt” where I believe you can set your keys manually, not sure about this but need to read more about it.
      Let me know if you find out how to do this :)

  18. Gustav says

    Hei Taiseer,
    First of all huge thanks for this. This was “the” article that helped me get most :) Have you any suggestions (ideas/ links) on how I can get my front web which is an MVC5 app to connect to the WebApi from part 1. To be concrete I like to use MVC5 frontweb that does same job as your angular project here. Any help is much appreciated.

    Regards
    Gustav

    • says

      Hi Gustav, glad that it was useful,
      Are u planing to use the API to support different applications or just your MVC 5 website? If just you have the MVC app then you can use the MVC5 template with individual accounts which contains all this features and much more such as 2FA and email confirmations. I find asp.net/identity is good place to check too. Hood luck in implementing the project!

  19. says

    Hello Taiseer

    Thanks for the wonderful article, I was able to implement the same and everthing works like a charm. But currently I am bit confused and need help.

    Instead of implementing the Web Api with an angularjs app I integrated the same with MVC app. Now my query is after authenticating and getting the token where should I store the token in cookie or session so that for subsequent request I can use that.

    • says

      You are welcome, glad it was useful,

      It is up to you where to store it, both should work, but If I were you I will store it in Cookie, as well you can store it in HTML5 local storage and access it via JS.

  20. Mark says

    Hi Taiseer,
    I’m new to API world… I download your application … setup it on local… and started exploring it…. everything working as expected… when i start Fiddler in parallel (so that i can record all activity) .. Login go to orders… logout… and then if i rerun (Replay> Reissue Request) orders in fiddler it gives me the orders… where as this is fired after user is logged off…

    So if any browser the authentication bearer token is set… it can pull any information… correct? (even after logout)… unless the claims/or token gets expired.

    Is there any way to avoid this?

    • says

      Hi Mark,
      Well there is no “direct” way to revoke granted access tokens or do “logoff”. if the user has the token then he can access the secured server resources until the token is expired.
      So in some situations it is better to use the refresh tokens along with the access token. So you issue short lived access token (30) mins and you use the refresh token to obtain new access tokens. The nice thing here that refresh tokens can be revoked from the backend system so there is control on them,

      You can read part 3 which talks about refresh tokens, and you can see how I manage to do the logoff in AngularJS application on part 2.

      Hope this answers your question.

  21. Louis says

    Hi Taiseer,

    I hope my comment and question does not come through twice, I did try comment from my phone, but it died, and I assumed it did not go through as I don’t see it here.

    Before I ask a question, I just would like to say thanks. for this brilliant article, and by the looks of things, many people do indeed feel the same. Certainly a job well done.

    I have implemented your concept into a web application that I am currently writing. While both parts in in our control, our API and UI does not reside on the same server. We have mainly done this so we could scale the various components in our system independently from each other. So your post did allow me to tie up a few loose ends, specially regarding bearer tokens.

    While everything works exactly as expected, I have one issue I was hoping you could help me with. I have just started integrating SignalR into the Angular application, I am sure you know that while SignalR does support various methods of performing its server connection, I would like that the “primary” mode does work. Websockets. The issue I am having is that with websockets we cannot attach the authorization header as we do for example with our api requests. So I have attached the token in the query string object exposed by SignalR. I started out by creating a new class implementing the SignalR Authorize attribute. In the AuthorizeHubConnection method, I can successfully get the token from the incoming request.

    It is now at this point where I am fairly stuck. From a bit of research I can see that I do need to set request.Enviroment["server.User"] = new ClaimsPrinciple(ticket.identity);

    The ultimate action part of my question would be, once I have the token in string format, how do I now get a AuthenticationTicket from this string and then pass that to the ClaimsPrinciple constructor?

    Regards

    Louis

    • says

      Hi Louis,
      You are welcome and really glad that my posts were helpful in implementing your “exciting” solution, I know about SingalR but never done serious development with it yet.
      To understand what you want to achieve here clearly; you have the encrypted/signed token on the back-end (AuthorizeHubConnection) method and you want to find a way to de-serialize it in order to build Authentication ticket and get identity/claims from this token string, is this right? If this is the case; currently I’ve no clear answer and I need to investigate it more. As I told you I’m not familiar with SignalR but I’ll try to find out something helpful.
      If you were able to find a solution for this please share it with us here.

      • Louis says

        Hi Taiseer,

        I have just got everything working. I would love to share this with people out there. I searched the net and could not find a solution and in turn just knuckled down and did some real coding for a change and invent stuff :)

        Could I possibly email the details through to you and you perhaps add it as a follow up on your post?

        that way people looking to implement any of these items will find all the related information together in one place?
        You can dm on Twitter @Louis_lewis

        Regards

        Louis

  22. brian kim says

    i try this everyting work but error log not showing on chrome..ie works file
    for example , when i try login with wrong password ie tell me i put wrong script but chrome not…

    do you have any idea?

  23. Mau says

    Thanks for the great article.

    A basic (maybe unrelated) question: why are you using the data- directives instead of ng- (as in data-ng-view instead of ng-view).

    Thanks!

  24. says

    Adding my gratitude to the long list of similar comments. Excellent article and almost a perfect match for my current app project. You just saved me a couple of days researching/ developing!

    Thanks!

  25. says

    Hi

    Great article and really helpful. I’m running my project with this setup and it works really fine. However if I only have the “Authorize” attribute on the api, I’m able to get access to my views and only the api would be able to reject me. How would you make use of the auth server on the router lever? Basically it could be wether a view/route should be available public or private (authenticated users)

    Best regards
    Rasmus

    • says

      Hi Rasmus, glad to hear that code is working perfectly on production environment.
      Well I’ll direct you to this link where you will have clear idea on how you can listen to the event “routeChangeStart” and check if this route can be accessed anonymously or it is only available for logged in users (with token).
      Let me know if this help in checking it on the Angular router service.

  26. Masoud says

    Hi,
    Thank you for your great effort and this beautiful sample , i could use your sample and it is useful for me, but i have a problem , I’ve updated the solution with nuget package manager and the version of owin changed to 3.0.0 and the version of asp.net web api became to 2.2 , then i always get an error access_denied after logging in google when i use external login , i want to know if you have checked your sample with the latest version of packages or not , and is there any solution for me

    • says

      You are welcome Masoud, always happy to help :)
      Yes I’ve been told this but really didn’t have the time to investigate what happened to OAuth.Google library. I’ll check this during weekend and will keep you updated. If you find solution please share it with us.

  27. says

    Hi Taiseer,
    Very good blog. It helps me so much.

    I have one question: Now, I apply your method to my personal project (not follow exactly your instructions).

    I applied:
    - ShellPage
    - authService / authInterceptorService
    - home / index / login controller

    And each time I press reload the page, the Top Menu do not display:
    - Welcome …
    - Logout

    Do you have any idea?

    • says

      Hi Trung, glad it was useful :)
      Well I believe that you forgot to call app.run method in your app.js file which is responsible to fill this data once the shell page is loaded, check the highlighted code here. If this didn’t work make sure you are using the “indexController” correctly on the shell page which is responsible for these feature.

  28. says

    I would very much like to add role based security – so that I can not only use [Authorize] but also [Authorize (Roles = "bla")]. I also would like to have a these roles and a user id returned to the ‘authService’.login method. Any suggestions?

    • says

      Hi,
      For question 1: You can set the roles manually in method “GrantResourceOwnerCredentials” after you validate the user credentials like this identity.AddClaim(new Claim(ClaimTypes.Role, “Admin”));
      The other option is when you register the user so you can assign it to a certain role using UserManager.AddToRoleAsync(currentUser.Id, “Admin”);

      For question 2: you need to add the below methods in class “SimpleAuthorizationServerProvider”:
      private AuthenticationProperties CreateProperties(OAuthGrantResourceOwnerCredentialsContext context)
      {
      IDictionary data = new Dictionary
      {
      { “userName”, context.UserName},
      { “role”, “pass your role”}
      };
      return new AuthenticationProperties(data);
      }

      public override Task TokenEndpoint(OAuthTokenEndpointContext context)
      {
      foreach (KeyValuePair property in context.Properties.Dictionary)
      {
      context.AdditionalResponseParameters.Add(property.Key, property.Value);
      }

      return Task.FromResult(null);
      }

      Hope this answers your question.

  29. Jaimie says

    Great Article. I’m wondering how you would implement forgot/reset password. Typically I would create a token in a reset table and send token (guid) in an email to the account if found. They then would need to go to that link and they could reset the password. I’m just not sure how that would work with this approach.

    I’m also wondering why you do not redirect to the Orders page after SignUp.

  30. Aibol says

    Hello Taiseer,

    I have one suggestion to the Angular app. In your code you add Authorization header to each XHR request. It could be much better to attach the bearer token only to those requests which are addressed to the RESTful service. Otherwise, unnecessary data are transfered with each HTML request.

  31. says

    Hi Taiseer,

    Thanks for this good article.

    A few things to notice :
    1- All your code controllers/services/etc needs to be wrapped by an Immediately-Invoked Function Expression (IIFE) to avoid polluting the global environment, so something like this

    (function(){
    ‘use strict’;
    /* Your code goes here */
    }());

    2- Just make sure that all your controllers/services are min safe by adding the injecting services to the string array before you define your function.

    Thanks again for your nice work.

    Omar

  32. says

    Hi Taiseer,

    First of all thanks for writing such good articles on Token Based Authentication. I am facing some issues while implementing SimpleAuthorizationServerProvider without refresh token.

    - Client is not logged out when browser closed.
    - Also access token is not getting expired.

    Could you please guide me where I am doing wrong.

    • says

      You welcome.
      You are not doing anything wrong, read part 1 carefully and notice that bearer tokens are not revokable, so I didn’t specify in the post that closing browser will remove token or log you out.

  33. says

    Thanks for this great article! It was very useful, and I’ve subscribed to your blog for updates.

    I’ve run into a problem: I tried adding a simple orders.html view to display the Orders generated by the API, like so:

    # Orders: {{orders.length}}

    {{order.orderID}}: {{order.customerName}} – {{order.shipperCity}}

    and added an ordersController.js:

    ‘use strict’;
    app.controller(‘ordersController’, ['$scope', 'ordersService', function ($scope, ordersService) {
    $scope.orders = ordersService.getOrders();
    }]);

    The API gets called and returns the canned orders JSON from part 1 of your tutorial. But the data doesn’t get assigned to the $scope.orders variable.

    What am I doing wrong? Thanks.

    • says

      Hi Doug, Thanks for subscribing :)
      Well I believe that there is issue in your current code, you can’t call $scope.orders = ordersService.getOrders() directly, getOrders method return a promise and you need to resolve it in the controller, check how I’m doing this in the repository here.
      Hope this answers your question.

  34. PJ says

    Hi, this really is an excellent article. I’ve built a few websites using a ASP MVC so have built MVC controllers which AngularJS has consumed data from.
    For my next application I was thinking about using ASP.NET Web API’s with AngularJS, where angular would get all it’s data from the API.
    Is this a good idea/architecture? OR should I stick with MVC and just write ‘proper’ WebAPIs for parts of the application I want to expose to other systems….?

    Many thanks

    PJ

  35. says

    Hi Taiseer,

    I have read your tutorials about token based authentication. I think It’s very cool . And, I try apply it for my project . I have some questions:
    I build app with different domains (multiple tenant) and using same authorize server . I think it same with google account . Example :
    - Authorize : authorize.com
    - example.com, user1.example.com
    - abc.com, user1.abc.com
    1. How to managed token and refresh token when it expired ?
    2. User only login as the first time and auto redirect every we access app. How do that?
    This is my ideal about sso and my questions . If you have any suggestion or ideal please let me know.

    Thanks,
    Quan Truong

    • says

      Hi Quan,
      Please find the answers “as for my understanding for your question because I don’t find it very clear”
      1 – When the access token expires, you will receive 401 response from the server, then the client application will be responsible to try and issue new access token using the refresh_token identifier he has before (grant_type=refresh_token) if it works correctly he will recieve a new access token. Check Nikolaj implementation where I’ve reference to this in my post where he implements this automatically.
      2 – This is something proprietary for your UI, once he logins and get the access token you can redirect him to any page/view you want and you store the access token locally so you start sending it with each request to any protected endpoint.
      Hope this answers your questions.

  36. Ederson says

    Could you please explain me in step 9 as the updated menu works after User login I’m not getting the update menu navigation that is required to change the css variable modicar for this condition and refresh the screen.
      <li data-ng-hide = "! authentication.isAuth"

  37. says

    Hello Ederson,
    Sure no problem, the navigation bar in the index.html page uses a controller named “indexController”, if you check the LOC https://github.com/tjoudeh/AngularJSAuthentication/blob/master/AngularJSAuthentication.Web/app/controllers/indexController.js#L9 you will notice that I’m passing the “authentication” object and checking if the user is authenticated or not, based on this I’m hiding/showing this list item. Hope this clarify your concern.

  38. Ederson says

    Hello Taiseer,

    It turns out that even with this object authentication returning true with the logged User is not updating my navigation menu not know if you need to add som css for checked as another example to run the hide-ng. Add.ng-ng-hide-hide-add-active also noticed that you do not add angular.module (‘app’, ['ngAnimate']); veriquei as another example has some part of css or javascript more work is needed to update the navigation bar?

  39. Ederson says

    Yes I am configuring the controller for the navigation section in the HTML but still not updated if I press F5 appears menus mean that my variable is populated in the controller.
    There’s something that is taken when clicked on login that makes updating the navigation menu?
    Even indexController being outside the ng-view it updates itself with the changes in the scope of the controller?

    This example will work if I upgrade the version of Angular v1.2.18?

  40. Marc says

    Hi,
    WONDERFUL work, thank you. All seems well except that navbar. The collapse button does not function at all when screen is small. NO expansion of menu items etc. Can you please post a working example of the navbar? Your menu looks nothing like any other example out there so I am confused. Then again, none of the examples posted on site work either. Everywhere I look the posts seem to say to use ui-bootstrap??????

  41. Marc says

    Thank you Sir!!!!!!!!!!!! Another noob question for you….
    I am trying to make a GET request work but the uri cannot be located. I keep getting 404 errors.

    Here is my webapi…

    // GET api/Permissions/GetPermissionByUser begin snippet
    [Authorize]
    [Route("GetPermissionByUser")]
    public IHttpActionResult Get(string userName)
    /// end snippet

    // The webapi config…
    config.Routes.MapHttpRoute(
    name: “DefaultApi”,
    routeTemplate: “api/{controller}/{id}”,
    defaults: new { id = RouteParameter.Optional }
    );

    // My javascript call…
    return $http.get(serviceBase + ‘api/Permissions/GetPermissionByUser’, userData).then(function (results) {
    return results;
    });

    // userData is a string with “userName” in it.

    Please advise if you can!

    Many thanks!

Trackbacks

Leave a Reply