1

I am writing code for a Angular SPA (Single Page Application).

  • In back-end it connects to an engine written in Java which does most of the processing(with which I am not concerned).

  • I am using UI Router to do the routing.

Problem

However there is a tricky situation that I am not able to accomplish.

  • When logging in, I make a API call which returns a response in JSON format.

  • If my call is successful(i.e. The login credentials match) I get a token in the returned JSON which is basically just a string that is combination of symbols, alphabets and numbers.

  • I am saving this in my rootscope and then accessing it as say $rootScope.myToken.

  • I then use the same token in subsequent API calls.

Now what I want to do in AngularJS is to redirect a user to the Login Page if he/she is not logged in and tries to access some URL directly via entering it in address bar.

I found a fairly simple method here Redirect on all routes to login if not authenticated . However I am not able to implement this with my token.

Question

What should I do to make this work with the token? Any other suggestion apart from this answer is also welcome.

PS: I have tried multiple methods on stackoverflow and I found them either not working in my context or overly complicated for the purpose.

UPDATE: I could successfully implement Simon H's answer in my code. However the issue I am facing is, this will ONLY redirect as I want AFTER I have logged in and out of my application at least one. If I try to access a page directly via URL without logging in and out at least once, this method fails and I can still access the page. Any tips?

2 Answers 2

1

there are lot of tutorials on the net for angular and jwt

I used those to develop something along the lines you want. They key part of the code is in the config

$httpProvider.interceptors.push(function($q, $location, $localStorage, $injector) {
    return {
        'request': function (config) {
            config.headers = config.headers || {};
            if ($localStorage.token) {
                config.headers.Authorization = 'Bearer ' + $localStorage.token;
            }
            return config;
        },
        'responseError': function(response) {
            /* 401, unauthorised:
                - bad username / password
                - token expired
               403, forbidden - notAdmin
            */ 
            // if(response.status === 401 || response.status === 403) {
            if(response.status === 401) {
                console.log("app.js: httpInterceptor caught 40x:", response);
                $injector.get('$state').go('login');
            }
            // Replace reponse with rejected promise to prevent rest of execution
            return $q.reject(response);
        }
    };
Sign up to request clarification or add additional context in comments.

3 Comments

I am a beginner in Web development, from what I have read, JWT is quite complicated. In my case, Token is nothing but a randomly generated string as I have mentioned in the question. Maybe it's not even a proper token and we are simply calling it a token. Will this still work?
Also, I am a bit confused where this piece of code should be? In the app.js file, which had my routing code, Should I be placing it inside the routing config? Or outside it?
UPDATE: I could implement this successfully in my code. However the issue I am facing is, this will ONLY redirect as I want AFTER I have logged in and out of my application at least one. If I try to access a page directly via URL without logging in and out at least once, this method fails and I can still access the page. Any tips?
0

Probably really late (because Angular2's out however I'm still answering if there are people still using 1.x) but I've worked on my own time with Node sending JWTs and Angular using it and I did it with UI router. Simon's solution will work however, I try not to touch the rootScope.

I implement 3 stuff to get it working. An Authorization service, the ngStorage module and Ui Router's state's resolve property.

ngStorage

It's a module that exposes $localStorage and $sessionStorage. You can add any object to it and it will set it in the browser until you clear it.

UI Router state's resolve

The offical docs of 1.x states that resolve is a property which maps to a function and will fire before the state is even initialized. Hence, this is a place where you can do micro configurations which the state is dependent on and it also does good with promises.

Authorization Factory

This is a factory which has 3 services. Login, Logout and isAuthenticated. The login service sets the token in the $localStorage upon success. In it's dependency injection, I inject it with ngStorage's $localStorage service alongwith $http and the others.


And now I explain how I do it.

I always point my default state to my home state instead of login state.

Instead of using rootscope, I make the Authorization Factory's login service post to the login endpoint of the server (the end point which will give me a fresh token). Once I receive the token, I set it to the $localStorage as my token.

Then, on resolve of my home state, I call the Authorization Factory's isAuthenticated service which simply checks if the token is set in the $localStorage. If it is not, it returns false. If it returns false, I can transition the home state redirect to my login state by $state.go('login');

What I get by this is, in every $http call application wide, I can inject the Authorization's isAuthenticated service in the controller and have it check for the token (which login service got and which isAuthenticated also has access to because they are in the same factory). If the token is present, I extract that token and send it with my data to the server. Then, my server can do additional token validation like checking it's expiry time and stuff and response back with 401s or 200s.

Now this may sound infuriating and seems like it's not DRY. But I'd like to say that I do all of this in one root parent state and attach all other states as the child states. The parent is abstract and hence can do the resolve and there is no need to initialize the state. The home can be the default non-abstract state.

I try to stay away from rootScopes and $watches and stuff and I keep them as a last resort always. Cheers!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.