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. Lana says

    I’m having a problem:

    I just setted the code below to allow roles to allow the roles admin, and have added my user to the role Admin and added the role to the database.

    Now when im trying to go to /tokens it says everytime Unauthorized.

    Already tried to allow lazyloading, not worked…

    Code:
    [Authorize(Roles = “Admin”)]
    [Route(“”)]
    public IHttpActionResult Get()
    {
    return Ok(_repo.GetAllRefreshTokens());
    }

    [Authorize(Roles = “Admin”)]
    [AllowAnonymous]
    [Route(“”)]
    public async Task Delete(string tokenId)

    • says

      Hi Lana, just answered the same question please check it here. As well you should not receive 401 when you call the “/token” end point it is unprotected endpoint.
      Let me know if you need further help!

  2. says

    Hi!

    I’m using this exempla with ionicframework.com and the only “problem” i get is i can’t hold the session.
    everytime i close the app, when i open they redirect to login page…
    I increase the login time on API, but nothing, i miss something?

    Thanks!

    • says

      Hi Daniel,
      Just to clarify there is no session between your hybrid mobile app and your API, your problem resides in not storing the token in HTML5 localStorage when you obtain the token from the Authorization server, there is nothing to do with increasing the token time.
      Make sure that you store the token locally on your app and you are sending it in the Authorization header for each request to a the API protected end points. That’s the areas you need to investigate and make sure they are working correctly in your hybrid mobile app.

  3. @Datz Me says

    I’m using Internet Explorer in testing this application but I can’t Login nor Sign up and i use this one to Google Chrome and no error happened. I used it in my Website and same problem with IE it cannot Login. Please help me what is the problem. It showed me an error “unsupported_grant_type”.. Note: Functional in anybrowser except Internet Explorer. What will I do to fix this problem?

  4. says

    How do you suggest debugging this locally? For serviceBase should we assign it the iis express url such as: var serviceBase = ‘http://localhost:49803/';, or should we just put everything in one project so we can use a relative URL? Is there a better approach?

    • says

      You can debug it while the projects are separated, if you need to debug the JS files you can use IE and set breakpoints, or you can use Google Chrome and set break points using developer tools.

      • says

        What I mean is, we have to replace this line:

        var serviceBase = ‘http://ngauthenticationapi.azurewebsites.net/';

        when debugging locally. What should we replace it with? It it’s just one project we can use a relative URL instead of an absolute one. What was the approach you took when debugging before deploying it to azure? Did you have the iis express URL hardcoded and then replace it before deploying to production?

        Thanks!

    • says

      Hi Tamer,
      There is no endpoint for validating the token in this tutorial, if you need to implement one you might need to store the tokens in DB. What you want to verify in the token? The claims inside it and if it is expired or not?

  5. paolo says

    Hi Taiseer,
    Thank you for detailed explanations.

    I faced the following problem:

    When use Chrome i have to click twice the login button because the first time I get the following errors:

    Failed to load resource: the server responded with a status of 400 (Bad Request) http://localhost:33484/token

    XMLHttpRequest cannot load http://localhost:33484/token. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:16583′ is therefore not allowed access. The response had HTTP status code 400.

    I have set the client allowed origin column to match my host: http://localhost:16583 and cors is enabled.

    the second time all work and the user is authenticated.

    ie and firefox work well.

    Thank you!
    paolo

      • paolo says

        Hi Taiseer,
        Thanks for rapid reply.
        I have checked in other chrome browser (mobile and other computers) and the result is the same, sometimes work fine and sometimes the first time I click to login button I get un error.
        For testing purpose I published the app, you may try to login,the test should be made more times opening and closing chrome.
        http://www.paolocostantini.it => demouser/demo123
        thanks

        • says

          I’ve checked and it is working fine at my end using Google chrome version (39.0.2171.65 m). Maybe you are facing this issue when you are logged in and you try to login again. I remember there is fix for this in the comments, you can search for it.

          • says

            Hi Rick,
            Is it doing the same behavior on the live demo application? If it is the same then there is issue with your Chrome browser, if it worked correctly then you need to check your source code and make sure your are setting the correct value for the AllowedOrigin. You can put it as * to allow all origins.
            Hope this help.

          • says

            Thanks for your detailed message, this is happening because you already logged in and your try to login again, try to call logOut function before you login again.

          • Ric says

            I was unable to login. In my case the solution was commenting the following line in SimpleAuthorizationServerProvider class:

            //context.OwinContext.Response.Headers.Add(“Access-Control-Allow-Origin”, new [] {“*”});

            I think it’s because Cors it’s already defined in Startup class:

            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

          • says

            Hi Rick, the line context.OwinContext.Response.Headers.Add(“Access-Control-Allow-Origin”, new [] {“*”}); is for enabling CORS for the “token” end point which is not part of the API (doesn’t inherit from “ApiController” class). If you are testing this from Rest Client not browser then it will work. But once you try it from browser it will fail. I do not know what is your exact issue but failing to login should not be related to CORS. If the issue still exists please elaborate more about it and hopefully I will be able to help.

    • Gyula says

      Hi

      After completing part 1 and 2 I face the exact same problem as Paolo. For IE and FF it works like a charm, for Chrome Version 39.0.2171.71 m the login gives CORS exception for the first try then it works the second time, and many consecutive times. I am not logged in or anything to cause this behavior.

      I’m looking forward to see if there is an easy fix to this
      Thank you

        • Gyula says

          Thank you for getting back to me. At the moment I don’t have time to implement part 3 but will do in the near future and get back to you. Also I will test on the live demo so I can have more information for you on this matter.

  6. morow93 says

    Good article! But I want to ask you about authorization. For example, about orders. When you try to load orders you check – user is authorized or not (if not authorized authInterceptor decide what need to do).
    But what if could be another situation? For example, you just load view (form for add another order) and you don’t need to call any web api cause you don’t need to get any data from database. You just wanna get the view. BUT THIS VIEW MUST BE AVAILABLE ONLY FOR AUTHORIZED USERS. How this problem can be resolved?
    Of course, when user try to submit this form his request will be rejected. But I need to disallow user to open any view which I want. For example, in user interface even couldn’t be a link which open this view but user can write this url directly in browser itself.
    Sorry for my English. From Russia with love. =)

  7. Saji says

    I get an error message that says “Sequence contains more than one element”, with the following exception.

    at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable1 source)
    at Microsoft.Owin.Security.AuthenticationManager.d__8.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    at System.Runtime.CompilerServices.TaskAwaiter
    1.GetResult()
    at System.Web.Http.HostAuthenticationFilter.d__0.MoveNext()
    — End of stack trace from previous location where exception was thrown —
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
    at System.Web.Http.Controllers.AuthenticationFilterResult.d__0.MoveNext()
    — End of stack trace from previous location where exception was thrown —
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
    at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()

    The request returns the appropriate response if I remove the “Authorize” tag from my API controller and comment-out the push of the auth interceptor to $httpProvider i. However, it doesn’t work if put the auth interceptor back in. This suggests to me that there’s something wrong in my auth interceptor, but my code is almost identical to what is used in the blog.

    The main difference is that my token is stored in a cookie instead of local storage.

    Do you know what is going wrong?

  8. Shaka says

    I have completed Part 1 & 2 of the token authentication, but I get an error when I try to try to store the username and token locally. I even get the error when I download your code. What step am I missing? My browser does support local storage.

    The error in the console reads…

    ReferenceError: isUndefined is not defined
    at Object.addToLocalStorage (http://localhost:39241/scripts/angular-local-storage.js:121:17)
    at http://localhost:39241/app/services/authService.js:31:33

    When debugging,the line in question is…

    localStorageService.set(‘authorizationData’, { token: response.access_token,userName: loginData.userName });

  9. Akinsanya Olanrewaju says

    Good day,

    Thank you so much for the tutorial, It’s very helpful.

    Haven look at the Back end and play with Web API which went fine. i was trying to run the sample application that i downloaded from git. I set the Web as startup then run the app, on signing up i get no response http://prntscr.com/5eustn. I haven change anything from the source code. I notice that yesterday when i was working on another copy of the file trying to make it run locally, i change the API web config connection string and the app.js service base http://prntscr.com/5eutix, it worked on my local system, but now i cant even get the new file working.

    Please can you help me figure out if there is any other configuration that i need to work on or fix.

    Thanks

    • says

      Hi,
      your issue is with CORS, complete to next part to see how you need to configure OAuth clients and set the allowed URI for clients correctly, The live application you see uses the same code in Github, so any failure most probably will be related to miss configuration at your local copy.
      Hope this helps.

  10. says

    Hello Taiseer,

    First of all, thank you for your great tutorial. It is what I was been looking for many months.

    I downloaded your demo project from codeproject and without any modification, I get the following error:

    XMLHttpRequest cannot load http://localhost/MyApp/token. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:32150′ is therefore not allowed access. The response had HTTP status code 400.

    It see that similar problems have been commented in the forum but I cannot find the reason of the problem.

    It only happens when I run the app under local IIS. Using IIS Express, everything works like a charm.

    I am not using refresh tokens and it is not related with the Client table records since it happens also when I enter a non-existing username in the login screen.

    Thank you

  11. francesco imbesi says

    I tried to do what I explain in the article in a Multi-Device-Hybrid App, but it does not work ..

    Does not see the sights in the tag NG-View!

    I would like to manage the login from a Multi-Device-Hybrid App with AngulaeJS.

    Can you suggest anything?

    not use Ionic Framework!

    BR

      • francesco imbesi says

        I used the example to login in a Multi-Device-Hybrid app. The code compiles correctly and in the emulator displays well. When I run the app in the device, the app does not Displayed all those who should be in “ng-view.” Not to be no errors and displays it enough! .. Should I use different components to display the content?

        I have tested by creating an app from scratch and creating routing rules similar to the following code:

        app.js

        (function () {
        ‘use strict';
        var meApp = angular.module(‘meApp’, [‘ngRoute’]);

        meApp.config([‘$routeProvider’, function ($routeProvider) {
        $routeProvider.
        when(‘/’, {
        templateUrl: ‘views/home/home.html’,
        controller: ‘homeCtrl’
        });
        }])

        meApp.config([‘$routeProvider’, function ($routeProvider) {
        $routeProvider.
        when(‘/map’, {
        templateUrl: ‘views/map/homeMap.html’,
        controller: ‘mapCtrl’
        });
        }])

        meApp.controller(‘homeCtrl’, function ($scope) {
        $scope.model = {
        message: “Sei in Home”
        }
        })

        meApp.controller(‘mapCtrl’, function ($scope) {
        $scope.model = {
        message: “Sei in Map”
        }
        })
        })()

        index.html

        Title

        <!–Go to home–>

        I would like to make this login system within a mobile device.

        br

  12. says

    I continue getting the following error:
    “XMLHttpRequest cannot load https://myweb.com:4001/token. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:32150′ is therefore not allowed access. The response had HTTP status code 404.”

    It works fine in my development PC, in local IIS and also in IIS Express, but it fails when I upload to the production server. The main difference is the https instead of http, but I do not think it is the problem.

    I followed your steps, in fact, for now I do not use refresh token, only the normal token, and within GrantResourceOwnerCredentials, I use:
    context.OwinContext.Response.Headers.Add(“Access-Control-Allow-Origin”, new[] { “*” });

    Using Fiddler, I can see the difference in the returned header, The https server returns:

    Access-Control-Allow-Credentials: true
    Access-Control-Allow-Origin: http://localhost:32150

    but the local IIS returns
    Access-Control-Allow-Credentials: true
    Access-Control-Allow-Origin: *

    I have no idea about the reason. Please, could you give me clue about it?

    Thank you

    • says

      Hi Dabiel, you need to make sure that you are setting the correct value for the response header “Access-Control-Allow-Origin” in the server to match your front-end full domain, in my tutorial you need to set this “GrantResourceOwnerCredentials” as you did, but is your front end using https too or http? I can from the response it is http. If it is https then tehy both should match.
      As well double check the order of registering Owin component in Startup class, they should be as this. Can you make sure that you are using the same version of of Owin and Owin.Cors(2.1.0) as the blog post.

  13. says

    Great post. Just a minor point of feedback that the authInterceptorService seems to always read from local storage. You actually do have in memory state for the auth credentials with you load into memory with fillAuthData. However this in memory state is never used and you are always reading from local storage in the interceptor service. Might be a small optimization there. Great work!

    • says

      Hi Taqi, the fullAuthData used to fill an object in the authService which runs only once when you run your application, this object is needed to decide if the user is logged in previously and mange the UI state, i.e. show/hide login link, display welcome {{userName}}, etc..

  14. tafs7 says

    Taiseer, we exchanged tweets, so I’m adding my question here to your blog as requested. I’ve got a requirement where upon sign in, the user needs to be shown a screen with a dropdown to select a “tenant” context before landing on home page. Users can be associated to many tenants, and their roles are different based on which tenant they’ve selected upon login.

    The tenant selection dropdown must be security trimmed and only show tenants that have been associated with the user in the DB (similar to the Azure mgmt portal, except you can’t change tenant context in the same login session, you’d have to logout and log back in….this last bit is not a business req).

    I wanted to leverage the authentication ticket and add a claim with the selected tenant id into the bearer token so that it functions very much like a role upon login….except the tenant selection is done after the user has logged in and the token has been created.

    I’ve managed to implement what i need using cookies auth and mvc razor views for the login and tenant selection pages, and then making the home landing page be the entry point of the angular app, not the entire HTML. But now I am in the processing of modifying the authentication to use tokens instead, as I don’t want the risk of CSRF from the angular app.

    I’ve got a bit of a “chicken vs egg” problem where I can’t security trim the tenant dropdown unless the user has been authenticated, but I also want to store the selected tenant in the auth bearer token as a claim. However by that point the token has already been created. The reason for me wanting to add the selection as a claim is so that it makes it easy for me to retrieve and use it on the server side, since the middleware is already decrypting and parsing out the claims from the token with every request. If I don’t leverage it, then I’ll have to implement a similar mechanism in parallel, just to grab that tenant. By grabbing it out of the token’s claims I trust that it was selected in a secure fashion, not just shoved into the request – kinda like a tampering of the request.

    • says

      Hi, thanks for your comment and apologies for the late reply.
      To be honest I’ve been trying to find solution for your scenario and each time I write something I come and delete it, it is not a simple use case, I’m thinking of creating custom authentication filter to protect the tenant end point and you issue temp access token (very short lived 1 min [enough for the user to select a tenant]), and after the user select tenant you simulate the login process and issue another access token.
      I’m not sure if this will work :(

      • tafs7 says

        I’ve run thru a dozen different scenarios, and each time I’d run through one, as you likely did when writing this reply, I’d find a flaw and start over.

        As you described, the only problem I see with issuing a short lived token is that it assumes the user won’t step away from the screen between logging in and selecting the tenant. I will also probably have to write logic in the angular app to make sure that if a user has authenticated but the tenant ID property is not stored in the authentication data (localStorage), that they cannot use the app and take them to the tenant selection view.

        What you described is very similar to what I’ve got now without tokens, but rather with cookies and the razor views. I log them in, then they select a tenant, I sign them out and then sign them in again but this time I add the tenant ID as a claim in the auth ticket.

        Thanks for taking some time to think thru this with me. I’ll spin some wheels and see what I come up with. This may merit a blog post if it succeeds…If you’re ever in the Dallas,Tx area, ping me and I owe you lunch :)

  15. says

    I am following this from scratch (not using github source demo). I don’t see where you specify the source of the LocalStorage module, it just exists in your project in the first screenshots. I have found two different ones via Google but neither seems to be the one you are using. I realize that I can get it from your github but I’d like to know the original source of the module.

    Thanks for a great set of tutorials. These are very well done and extremely helpful!

    • says

      Hi Justin, You are welcome :)
      I’m using the Angular Local Storage Module and here is the one I’m using in this project. Be careful that there might be changes with local storage API if you grabbed the latest one from CDN or Github. Recommend you to use the same version I used in this tutorial if you want to follow along without any issues. Good luck.

      • says

        I had some dependency hell issues with NuGet – it wouldn’t pull your specified version. So I’m already rolling the dice using latest versions. Even the latest versions of Owin claim to reference v3.x but actually load 2.x which compiles but immediately throws runtime errors. You have to specifically install the latest Owin sub dependencies that have the wrong version numbers via NuGet. Then everything works (but it’s a newer version than yours).

        I’m competent with Angular, MVC and WebAPI. I’m new to Asp.NET Identity, OWIN, OAuth2 and Cors so those are the real areas of learning here for me. Ultimately I want to end up with three application components: an OWIN/OAuth2 User Auth server that can function like a really light SSO, a WebAPI that uses tokens to authorize access to specific endpoints, and an Angular SPA that gets the token from Auth and resources from API.

        This tutorial is an excellent starting point.

  16. says

    Hi Taiseer,

    I’m using refresh tokens in my web api and also my front end is using angularJS, when I request some data to the web api and I’m not authenticated I received a 401 code response and I request a new token and try to make the previous request again with the new token, the main problem here is when I get a 401 code for a sencond time I enter in an infinite loop because even if I’m authorized but if I dont have the permissions to access the uri I will received a 401 code and the interceptor will keep trying to refresh the token and retry the request.

    if (rejection.status === 401) {
    var authentication = $injector.get(‘authentication’);
    authentication.refreshToken().then(function (response) {
    _retryHttpRequest(rejection.config, deferred);
    }, function () {
    authentication.logOut();
    $injector.get(‘$state’).go(“page.login”);
    deferred.reject(rejection);
    });
    }

    I read here: http://www.codeproject.com/Articles/655086/Handling-authentication-specific-issues-for-AJAX-c that you can overwrite the AuthorizeAttribute filter and the provide a custom error code for both cases
    401 code for unauthorized requests
    403 code for forbidden requests
    Do you think this is the rigth way to do it? or do you have any suggestion to acompplish this issue?

    Thanks,

  17. says

    Hello Tayseer, GREAT Tutorial,, really life saver..

    BUT I have a problem..

    the web API is working great,, the signup,, registration views are working perfectly…

    my problem is with the orders page… or in my demo I called it Projects.. the projects controller is working fine I tested it using Postman,, with authorization and using the token,, it works fine,, but when using on the page it gives me error
    “OPTIONS http://localhost:6065/api/projects net::ERR_CONNECTION_REFUSED”.

    The Interceptor is working fine,, it gets the authentication token from the local storage… and save it into the header object.. after that I couldn’t debug..

    I am lost and I don’t know what to do,.. please help

    here is the code for my controller :

    ‘use strict';
    app.controller(‘projectsController’, [‘$scope’, ‘projectsService’, function ($scope, projectsService) {

    $scope.projects = [];

    projectsService.getProjects().then(function (results) {

    $scope.projects = results.data;

    }, function (error) {
    //alert(error.data.message);
    });

    }]);

    and this is the code for my service…

    ‘use strict';
    app.factory(‘projectsService’, [‘$http’, ‘ngAuthSettings’, function ($http, ngAuthSettings) {

    var serviceBase = ngAuthSettings.apiServiceBaseUri;

    var projectsServiceFactory = {};

    var _getOrders = function () {

    return $http.get(serviceBase + ‘api/projects’).then(function (results) {
    return results;
    });
    };

    projectsServiceFactory.getProjects = _getOrders;

    return projectsServiceFactory;

    }]);

      • says

        Thanks Mohammad for your message, If it is working on fiddler and not working from web browser then I suspect you didn’t configure CORS correctly. Make sure you are not receiving 405 response. There should preflighted request to the API which sets the Access-Control-Allow-Origin header. Hops this solves the issue.
        If you configured CORS correctly please check this link maybe it is related to chrome and accessing local storage

        • says

          Thanks Taiseer for the reply,, now I am sure it is a CORS issue,, I checked it in IE and Firefox, firefox tool mentioned that it is a CORS issue.. I’ve configured the CORS in the startap class as you mentioned in the Tutorial, I wonder if there is any further configuration there.. check my startap class:

          using AprilIT.ProjectManager.API.Providers;
          using Microsoft.Owin;
          using Microsoft.Owin.Security.OAuth;
          using Owin;
          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Web;
          using System.Web.Http;

          [assembly: OwinStartup(typeof(AprilIT.ProjectManager.API.Startup))]
          namespace AprilIT.ProjectManager.API
          {
          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);
          }
          public void ConfigureOAuth(IAppBuilder app)
          {
          OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
          {
          AllowInsecureHttp = true,
          TokenEndpointPath = new PathString(“/token”),
          AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
          Provider = new SimpleAuthorizationServerProvider()
          };

          // Token Generation
          app.UseOAuthAuthorizationServer(OAuthServerOptions);
          app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

          }

          }
          }

          Why it is causing a problem only when loading the Projects class, why it is not doing the same for the Token class???

          again thanks for your help…

          • says

            Ok,, here is my last investigation…

            when runing the registration page using view in browser with out running the web API project it gives me cross origin error… BUT when I run the web api project, then view the client website in the browser the registration works fine, it transfers me to the login page.. I login successfully,,., BUT again when I go to the projects /orders page it is simply give me the error of CORS is not enabled.. I am literally losing my mind here…

  18. Kelvin says

    Hello Everyone,

    Please i would appreciate any urgent answer/help on the above subject. Actually, am about to start working on a project that involves developing a website where registered employees (on a remote desktop application) can come and view their basic information.

    I understand i need to make some API calls that would fetch the data from the remote desktop database and render it on html for the users.

    Please can anyone provide me with useful tip/tutorial/guide/reference on how to start?

    Thanks in advance.

  19. says

    Hello Tayseer,

    I have a small question… I am using Parsley validation with my forms,,, and I am using Parsley remote to validate using ajax to check if user exists in the database already… it has a nice way to give a url and check the status code…if not 404 then the user is already existed and you cannot use it….

    the issue here.. if the AccountController is Authenticated,, and I want only authorized users to use it… it works fine when using ngresource and in the service it will just be called by the interceptor to modify the headers… BUT out side the service it doesn’t use the interceptor..

    In other words my validation method is in the Controller.js file.. it doesn’t use a service.. and the interceptor is not being called…. HOW can I make the interceptor work outside the service…this code shows the validation method inside my controller

    window.ParsleyExtend = {
    asyncValidators: {
    checkusername: {
    fn: function (xhr) {
    return 404 === xhr.status;
    },
    url: authService.serviceBase + ‘api/account/CheckUserName/’ + $(‘[name=”userName”]’).text()
    },
    checkemail: {
    fn: function (xhr) {

    // console.log($(‘[name=”email”]’)); // jQuery Object[ input[name=”q”] ]

    return 404 === xhr.status;
    },
    url: authService.serviceBase + ‘api/account/CheckEmail/’ + $(‘[name=”email”]’).text()
    }
    }
    };

    any idea :)

  20. Besa says

    Hello,

    I am doing a website and for the authentication I followed your tutorial. I deleted the global.asax.cs and instead I used the startup.cs file. When I try to publish the file, the server is searching for the Global.asax therefor the publishing proccess fails.
    What should I do in this case? Is there any solution or I should bring back the Global.asax.cs?

    Thank you for the great tutorial. It is the best I have seen online

    • says

      It is hard to troubleshoot the issue, but it seems there is code depends on Global.asax file. Is this MVC application or Web API? Did you start from scratch or used VS templates?

      • Besa says

        Its MVC application. I manage to push the project to the server by adding the Global file back in the project and it works fine. For now it’s OK but I am not sure if it is the best solution.

        Let me know if you have any suggestion.

        Thank you so much

  21. Savinder says

    Hi Taiseer,
    Thanks for the great article.
    I have scenario. Here I need to open a new tab/window, to open a new angular app (based on certain user input). On server side I have MVC controller route that will render my new app html view.
    Problem is I am not able to authenticate. How can I pass the jwt in this post. The click handler in the current controller is
    var link = ‘/App/Create/’ + a + ‘/’ + b;
    window.open(link, ‘_blank’);

    Please advise!
    Thanks,
    Savinder

    • Savinder says

      Hi Taiseer, I kinda worked around it. The html for new angular app is allowed to be loaded unauthenticated. Then in a round trip the angular app, taking jwt from localstore, loads the state (authenticated).
      I would appreciate your expert opinion on that.
      Thanks,
      Savinder

  22. Setu Trivedi says

    Hi..On execution of below code in authService.js,
    $http.post(serviceBase + ‘token’, data, { headers: { ‘Content-Type': ‘application/x-www-form-urlencoded’ } }).success(function (response)

    I am getting below error,
    POST http://localhost:12901/token 404 (Not Found)
    Is token folder to be created in the project….? Can you please explain….?

  23. Tim says

    Hi Taiseer,

    I have a question for you about the fillAuthData mehod in the authService. When I call the method from run in the app.js file, I get an undefined error. If I removing the call to fileAuthData on run, I am able to call the register, login and logout methods successfully. But when I call the fillAuthData, I get an undefined error. I check the localStorage in chrome and the token is there. But I can’t read it. Do you have any idea why this would be?

    Thanks
    Tim

  24. says

    var serviceBase = ‘http://ngauthenticationapi.azurewebsites.net/';
    here u r using this url instead if i try mine its not working,not showing error message too plz gimme suggestions
    ..

  25. 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"

  26. 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.

  27. 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?

  28. 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?

  29. 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??????

  30. 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

  1. […] Jeff Dickey Create a TV Show Tracker using AngularJS, Node.js and MongoDB – Sahat Yalkabov AngularJS Token Authentication using ASP.NET Web API 2, Owin, and Identity – Taiseer Joudeh Building with Gulp – Callum Macrae Emulators Written in JavaScript – […]

Leave a Reply