I have an application that will be deployed at two places. There would be one master and one slave. I have a requirement that some of the requests should be satisfied by slave and others by master.
For this, I am sending login request to master on successful login to slave. I am able to achieve this.
My problem is, when i try to access any resource from master(request a resource from master originating from slave) after logging in, It is giving unauthorized(401) error.
Login controller:
$http.post('j_spring_security_check', payload, config).success(function(data, textStatus, jqXHR, dataType) {
if ($scope.rememberme) {
var user = {
username: $scope.username,
password: $rootScope.encryptPass($scope.password, true),
rememberme: $scope.rememberme
};
localStorage.setItem('user', JSON.stringify(user));
} else {
localStorage.removeItem('user');
}
$rootScope.pingServer();
$rootScope.retrieveNotificationCount();
$http.post('http://localhost:9090/context/j_spring_security_check',payload, config).success(function(data, textStatus, jqXHR, dataType) {
$rootScope.pingServer();
}).error(function(data, status, headers, config) {
});
});
app.js
rootapp.config(['$httpProvider', function(httpProvider) {
httpProvider.interceptors.push(['$rootScope', function($rootScope) {
return {
request: function(config) {
config.headers = config.headers||{};
config.headers['withCredentials'] = true;
config.headers['useXDomain'] = true;
return config;
}
}
}]);
My server has a filter
#Singleton
public class ResponseCorsFilter implements Filter {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
if (servletResponse instanceof HttpServletResponse) {
if (request.getMethod().equals("OPTION") || request.getMethod().equals("OPTIONS")) {
System.out.println("In Options");
if (request.getServletPath().equals("/j_spring_security_check")) {
System.out.println("request path match");
alteredResponse.setStatus(HttpServletResponse.SC_OK);
addHeadersFor200Response(alteredResponse);
return;
}
}
addHeadersFor200Response(alteredResponse);
}
filterChain.doFilter(servletRequest, servletResponse);
}
private void addHeadersFor200Response(HttpServletResponse response) {
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Credentials", "true");
response.addHeader("Access-Control-Allow-Methods", "ACL, CANCELUPLOAD, CHECKIN, CHECKOUT, COPY, DELETE, GET, HEAD, LOCK, MKCALENDAR, MKCOL, MOVE, OPTIONS, POST, PROPFIND, PROPPATCH, PUT, REPORT, SEARCH, UNCHECKOUT, UNLOCK, UPDATE, VERSION-CONTROL");
response.addHeader("Access-Control-Allow-Headers", "useXDomain, withCredentials, Overwrite, Destination, Content-Type, Depth, User-Agent, Translate, Range, Content-Range, Timeout, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control, Location, Lock-Token, If");
response.addHeader("Access-Control-Expose-Headers", "DAV, content-length, Allow");
response.addHeader("Access-Control-Max-Age", "86400");
}
}
Am I missing anything?
You are incorrectly setting withCredentials as a request header. This is XHR option and should be present directly on the config:
config.withCredentials = true;
This option will enable cookies for your requests. Your requests will be able to include JSESSIONID, thus allowing HTTP session where Spring Security stores information about the authentication.
And as discussed in the chat (see question comments) - be aware that if the two servers are running on the same domain, they will share cookies. That might cause issues (sending incorrect JSESSIONID) so you need to access those servers under different host name.
Related
When I am trying to authenticate an user from AngularJS, I am seeing this warning in Spring Boot log:
[WARN ] 2017-02-04 17:09:20.085 [http-nio-8080-exec-1] DefaultHandlerExceptionResolver - Resolved exception caused by Handler execution: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'null' not supported
And the browser response is:
415 Unsupported Media Type
My LoginController:
#RestController
// #RequestMapping("/")
public class LoginController {
public Logger logger = LoggerFactory.getLogger(this.getClass());
#RequestMapping(value = "/login", method = RequestMethod.GET,
consumes = MediaType.APPLICATION_JSON_VALUE
/*produces = MediaType.APPLICATION_JSON_VALUE*/)
public ResponseEntity<Admin> login(#RequestBody UserDTO user, BindingResult result, WebRequest request) {
logger.info("********** Inside login of LoginController **************");
Admin authenticatedUser = (Admin) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
HttpStatus httpStatus = null;
if (authenticatedUser == null) {
httpStatus = HttpStatus.NOT_FOUND;
} else {
httpStatus = HttpStatus.OK;
}
return new ResponseEntity<Admin>(authenticatedUser, httpStatus);
}
}
My AngularJS code:
service.login = function(user, successHandler, errorHandler) {
// Obtain a CSRF token
loginResources.options().$promise.then(function (response) {
console.log('Obtained a CSRF token in a cookie', response);
// Extract the CSRF token
var csrfToken = Cookies.getFromDocument($http.defaults.xsrfCookieName);
console.log('Extracted the CSRF token from the cookie', csrfToken);
// Prepare the headers
var headers = {
'Content-Type': 'application/json'
};
headers[$http.defaults.xsrfHeaderName] = csrfToken;
console.log("Before calling /login, user : ", user);
// Post the credentials for logging in
$http.get(ApiBasePath + '/login', user, {headers: headers})
.success(successHandler)
.error(function (data, status, headers, config) {
if (isCSRFTokenInvalidOrMissing(data, status)) {
console.error('The obtained CSRF token was either missing or invalid. Have you turned on your cookies?');
} else {
// Nope, the error is due to something else. Run the error handler...
errorHandler(data, status, headers, config);
}
});
}).catch(function(response) {
console.error('Could not contact the server... is it online? Are we?', response);
});
};//login function ends
I have an exactly same registration controller with an exactly same AngularJS register function (with different endpoint of course), but that works perfectly.
I doubt one thing though, when I am using Spring Security, do I really need the LoginController with the endpoint /login or the security configuration will take care of that? My security config:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/*/**").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/register").permitAll()
.antMatchers("/", "/**/*.css", "/**/**/*,css",
"/**/*.js", "/**/**/*.js").permitAll()
.antMatchers("/dashboard", "/dasboard/**", "/logout").authenticated();
// Handlers and entry points
http
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
http
.formLogin()
.successHandler(authenticationSuccessHandler);
http
.formLogin()
.failureHandler(authenticationFailureHandler);
// Logout
http
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(logoutSuccessHandler);
// CORS
http
.addFilterBefore(corsFilter, ChannelProcessingFilter.class);
// CSRF
http
.csrf().requireCsrfProtectionMatcher(
new AndRequestMatcher(
// Apply CSRF protection to all paths that do NOT match the ones below
new NegatedRequestMatcher(new AntPathRequestMatcher("/", HttpMethod.OPTIONS.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/", HttpMethod.GET.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/", HttpMethod.POST.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/", HttpMethod.HEAD.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/", HttpMethod.TRACE.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/css/**", HttpMethod.GET.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/js/**", HttpMethod.GET.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/js/**/**", HttpMethod.GET.toString())),
// We disable CSRF at login/logout, but only for OPTIONS methods
new NegatedRequestMatcher(new AntPathRequestMatcher("/login*/**", HttpMethod.OPTIONS.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/logout*/**", HttpMethod.OPTIONS.toString())),
//Disable CSRF at register for all methods
new NegatedRequestMatcher(new AntPathRequestMatcher("/register*/**", HttpMethod.OPTIONS.toString()))
)
);
http
.addFilterAfter(new CsrfTokenResponseCookieBindingFilter(), CsrfFilter.class); // CSRF tokens handling
}
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authProvider());
}
#Bean
public DaoAuthenticationProvider authProvider() {
final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(encoder());
return authProvider;
}
#Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder(11);
}
Finally I got the answer. It is true, if I try to send json object instead of request parameters, that I have to use Custom UserNamePasswordAuthenticationFilter. It is also true, I have to use POST.
Thanks #dur for pointing that.
Finally, a big thanks to this post. Without this post, I wouldn't have possibly find out how to customize the filter.
Struggling for quite some time. I am having Angular.js at front with Java/J2EE (RESTFul) at the backend with Spring security (Enabled Cors-filter). Spring security works perfectly fine except when I try to enable csrf protection. Below is my code I tried for csrf:
My CSRF filter
public class CsrfHeaderFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
}
Security configuration has below code:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.formLogin()
.successHandler(authSuccess)
.failureHandler(authFailure)
.and()
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.antMatchers("/admin/**").access("hasRole('ADMIN')")
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.and()
.addFilterBefore(corsFilter, HeaderWriterFilter.class)
.addFilterAfter(csrfHeaderFilter, CsrfFilter.class)
.csrf().csrfTokenRepository(csrfTokenRepository());
//.csrf().disable();
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
Had to modify CORS filter to add X-XSRF-TOKEN header name inside Access-Control-Allow-Headers as initially it was giving this error.
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-XSRF-TOKEN, x-requested-with, Content-Type");
chain.doFilter(req, res);
}
My angular js code:
$scope.login = function () {
$http.post("http://localhost:9090/cynosureserver/login", "username=" + $scope.user.name +
"&password=" + $scope.user.password, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-XSRF-TOKEN': $cookies.get('XSRF-TOKEN')
}
}).then(function (data) {
alert("login successful" + JSON.stringify(data));
}, function (err) {
alert("error logging in" + JSON.stringify(err));
});
};
I have debug points set up. After login form it goes to Csrf filter. But never hit my "CustomUserDetailsService". The problem is I always get 403 response saying:
HTTP Status 403 - Expected CSRF token not found. Has your session expired?
If I make a simple Get request it is successful and also "XSRF-TOKEN" cookie is received inside Response Header.
But for my post method I am unable to proceed.
I am seeing below:
Status Code:403 Forbidden
Remote Address:[::1]:9090
Response Headers
Access-Control-Allow-Headers:X-XSRF-TOKEN, x-requested-with, Content-Type
Access-Control-Allow-Methods:POST, GET, PUT, OPTIONS, DELETE
Access-Control-Allow-Origin:*
....
Set-Cookie:JSESSIONID=5DE6DB8B5E31DC77DC4ED28600445615; Path=/cynosureserver/; HttpOnly
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block
Request Headers
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate
...
Content-Type:application/x-www-form-urlencoded
Host:localhost:9090
Origin:http://localhost:9000
Referer:http://localhost:9000/
X-XSRF-TOKEN:7c2057b5-0f1a-4dc1-bab4-c8f000a2ae2d
Form Data
username:manisha
password:123456
I tried many different combinations but nothing seems to work, Please help me - what am I missing ? I am totally clueless here. Sorry for lengthy post.
I am getting this error shown on browser console:
XMLHttpRequest cannot load http://localhost:8080/api/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9009' is therefore not allowed access.
The environment I am using are:
Backend- Spring Boot
Front End- Angularjs
Web Server- Grunt
On server, I am already defining headers in request and response as:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Access-Control-Allow-Origin", "*");
httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE,PUT");
httpResponse.setHeader("Access-Control-Max-Age", "3600");
httpResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization, Content-Type");
if (httpRequest.getMethod().equals("OPTIONS")) {
httpResponse.setStatus(HttpServletResponse.SC_ACCEPTED);
return;
}
}
I already found this question on this link No 'Access-Control-Allow-Origin' header is present on the requested resource but couldn't find the appropriate solution.
Here is the browser network image:
Your server should add the proper CORS headers for preflight/actual CORS requests. I wouldn't recommend implementing your own Filter, since this is a rather complex specification.
As of 4.2, Spring Framework supports CORS with a global configuration or with a Filter - see this blog post for more information.
If you're using Spring Boot, version 1.3.0 (to be released soon) will integrate this support.
You need to enable CORS(Cross Origin Resource Sharing) on your web server. Please refer to this resource.
You need to set your response header to:
Access-Control-Allow-Origin: *
This link has all the info needed to set CORS
Enabling CORS for all domain is not a good practice, so you should restrict it when everything is up and running.
Another workaround is to have a separate API for curl request
Call a URL in your own API and access the data using your server side with cURL or something. I have a current working project with same situation (Laravel + AngularJs).
My sample code for the remote auth check with cURL request.
Code is in Laravel-PHP format, I hope you can convert to the language you are working on.
Requester function:
public function curlRequester($url,$fields)
{
// Open connection
$ch = curl_init();
// Set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
// Execute post
$result = curl_exec($ch);
// Close connection
curl_close($ch);
$result_json_decoded = json_decode($result, true);
return $result_json_decoded;
}
Controller function
public function login()
{
// set POST params
$fields = array(
'username' => Input::get('username'),
'password' => Input::get('password')
);
$url = 'http://www.this-is-api-url.com/login';
$result = $this->curl->curlRequester($url,$fields);
return response()->json($result);
}
Angular request function
$scope.authCheck = function(){
$http({
url:'http://www.our-project-url/login',
method:"post",
data:{"username": "rameez", "password":"rameezrami"}
})
.success(function(response) {
if(response.status==1){
$location.path("/homepage");
}else if(response.status==0){
$scope.login_error_message_box = true;
$scope.login_error_message_text =response.message;
}
});
}
Your Filter is right, You should include your filter as a component and put it where it can be scanned by spring
#Component
public class CORSFilter implements Filter{
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, res);
}
#Override
public void destroy() {
}
}
You need to also make an update in your angular code to allow CORS via AJAX.
myApp.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}
]);
If the above doesn't work, you may need to also add the following:
myApp.all('/*', function (request, response, next) {
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Headers", "X-Requested-With");
response.header("Access-Control-Allow-Methods", "GET, POST", "PUT", "DELETE");
next();
});
As noted by #Marged you want to be cautious about the "*" and I would highly recommend replacing that with your domain(s).
I am trying to make cross-domain requests with Angularjs 1.4.5.
But can't get success. I have configured $httpprovider
.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.common['Accept']= "application/json, text/plain, */*";
$httpProvider.defaults.headers.put["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8";
$httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8";
$httpProvider.interceptors.push('authenticationFailedInterceptor');
}])
But still con't get success. How to enable CORS support with Vert.x 2.x http server.
CORS is supported in Vert.x 3.x but Right now I can't upgrade Vert.x.
have you tried with something like this on your responses?
vertx.createHttpServer()
.requestHandler(function (req) {
req.response()
.putHeader("content-type", "text/plain")
.putHeader("Access-Control-Allow-Origin", "*")
.putHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
.putHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
.end("Hello from Vert.x!");
}).listen(8080);
for sure, you have to modify this to your needs... but the changes has to be done in the server and at least, you need these three headers.
Complete example to enable cors:
We need to create two route matcher.
One helps to enable cors and other handle the requests.
Below is to enable cors. It Accept all request and add all the required headers needs to enable cors. After that we need to hand over request to the actual route matcher to handle request. We have that by the name secureRoutes.
RouteMatcher routeMatcher = new RouteMatcher();
routeMatcher.options(".*",new Handler<HttpServerRequest>() {
#Override
public void handle(final HttpServerRequest request) {
request.response().putHeader("Access-Control-Allow-Origin", "*");
request.response().putHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
request.response().putHeader("Access-Control-Allow-Headers", "accept, authorization, content-type, email");
request.response().end();
}
})
.all(".*",new Handler<HttpServerRequest>() {
#Override
public void handle(final HttpServerRequest request) {
request.response().putHeader("Access-Control-Allow-Origin", "*");
secureRoutes.getRouteMatcher().handle(request);
}
});
Another route matcher:
public class SecureRoutes {
private static final RouteMatcher routeMatcher = new RouteMatcher();
#Inject
protected Container container;
#Inject
private SigninController signinController;
#Inject
private SignupController signupController;
#Inject
private OauthController oauthController;
#Inject
ClientNetworkSignalController clientNetworkSignalController;
public void initRoutes() {
// APP routes. they use User token for authentication
routeMatcher.get("/", new Handler<HttpServerRequest>() {
#Override
public void handle(final HttpServerRequest request) {
request.response().putHeader("Cache-Control",
"public, max-age=86400");
request.response().sendFile("web/public/index.html");
}
});
routeMatcher.post("/signin", signinController.signin());
routeMatcher.post("/signup", signupController.signup());
routeMatcher.post("/oauth2/token", oauthController.token());
routeMatcher.post("/oauth2/invalidate_token", oauthController.invalidateToken());
}
public RouteMatcher getRouteMatcher() {
return routeMatcher;
}
}
Now finally add requestHandler to server:
server.requestHandler(routeMatcher).listen(port,
host, new Handler<AsyncResult<HttpServer>>() {
public void handle(AsyncResult<HttpServer> asyncResult) {
if (asyncResult.succeeded()) {
logger.info(s + ": Started on " + host + ":"
+ port);
} else {
logger.info(s + ": Unable to start server.\n "
+ asyncResult.cause());
}
}
});
You may have a question What is the use of http options type request handler. The answer is for that is very interesting. Javascript is a secured language that do not allow Cross origin Http request. So, to allow cross origin request javascript send a options type request for each http request request and check weather CORS is supported or not. In such Javascript hits server two times one to check cors is supported or not and one to fatch data.
I'm here because I tried everything and I don't understand what I'm doing wrong.
As a backend, I use Spring MVC, Rest and Spring Security. I'm using a custom authentication's system based on tokens (entirely stateless). I've also a CORS's filter, because my front app is not running on the same server.
So here's what I did in angularJS, in order to get authenticate when I want to access a protected resource:
I've created an interceptor that change each request to add the token found from a cookie
I add a custom header on the request
Here's what my interceptor do:
request: function(config) {
var token = $cookieStore.get("token");
if (token && token.key) {
config.headers["X-Auth-Token"]=token.key;
}
console.log(config.headers);
return config || $q.when(config);
}
But when I try to access a protected resource, even if the token is still valid, it never puts the X-Auth-Token headers on the request! It tried to send an option's request and failed with a 401 error!
But if I do the same with a url parameter (like token=....), the interceptor works as expected...(I've implemented both system : by parameter and by header)
What I don't understand is why the header is not put as expected?? and why it works perfectly with something like POSTMAN for instance?
Please help, I'm losing my hairs with this...
It's probably cleaner to do this instead of your accepted answer.
if (request.getMethod().equals("OPTIONS")) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(request, response);
}
I fixed the problem by changing my filter like this:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
LOG.info("goes on the filter");
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Origin, Authorization, X-Auth-Token");
response.addHeader("Access-Control-Expose-Headers", "X-Auth-Token");
if (request.getMethod().equals("OPTIONS")) {
try {
response.getWriter().print("OK");
response.getWriter().flush();
} catch (IOException e) {
LOG.error(e.getMessage());
}
} else {
chain.doFilter(request, response);
}
}
Not sure if this will solve your issue, but $cookieStore can only get/set strings, so the following:
var token = $cookieStore.get("token");
if (token && token.key) {
Will never evaluate to true.