Keycloak token not active with angularjs - angularjs

I have spring boot backend app with Angular js app. The login process and initial backend communication are successful. After some idle time, the front end will show 403 forbidden with token not active on the backend console.
The code below contains refresh token, But it seems not working.
// use bearer token when calling backend
themesApp.config(['$httpProvider', function($httpProvider) {
var isExpired = keycloak.isTokenExpired();
var token = keycloak.token;
if (isExpired) {
keycloak.updateToken(5)
.success(function() {
$httpProvider.defaults.headers.common['Authorization'] = 'BEARER ' + token;
})
.error(function() {
console.error('Failed to refresh token');
});
}
$httpProvider.defaults.headers.common['Authorization'] = 'BEARER ' + token;
}]);
Error on the backend
2017-05-29 10:08:23.715 ERROR 5072 --- [nio-8080-exec-3] o.k.a.BearerTokenRequestAuthenticator : Failed to verify token
org.keycloak.common.VerificationException: Token is not active

Something must be wrong on the Keycloak Server, Token not active means token being is expired or is used before it gets valid. Could it be that the time/date is wrong on your KC server ?

you can config the 'Session Idle Time' here:
I had the same issue and handle it with an automatical logout. So the user has to login again.

In your code:
var token = keycloak.token;
you define the value of token once. After the update you have to set it again:
// use bearer token when calling backend
themesApp.config(['$httpProvider', function($httpProvider) {
var isExpired = keycloak.isTokenExpired();
var token = keycloak.token;
if (isExpired) {
keycloak.updateToken(5)
.success(function() {
// UPDATE THE TOKEN
token = keycloak.token;
$httpProvider.defaults.headers.common['Authorization'] = 'BEARER ' + token;
})
.error(function() {
console.error('Failed to refresh token');
});
}
$httpProvider.defaults.headers.common['Authorization'] = 'BEARER ' + token;
}]);

Related

Request failed with status code 401 at createError "Unauthenticated"

I'm using laravel with reactjs I'm getting this problem when I'm doing logout
axios.defaults.withCredentials = true;
// axios.defaults.headers.common = {'Authorization': 'bearer ' + localStorage.getItem('auth_token')}
axios.interceptors.request.use(function (config){
const token = localStorage.getItem('auth_token');
// config.headers["Authorization"] = "bearer " + token;
config.headers.Authorization = token ? `Bearer ${token}` : '';
return config;
});
So what does that logout api do this is clearly a permission error coming from laravel. Show the logout method from the backend. Also check your network you can see the full message there.

How to refresh JWT token using interceptors in angularjs?

I am having my application back-end implementation in Lumen which gives a JWT token every time a user logs in. The front end I am using Angular to save the token in the local storage and also I am adding it to all the headers in the subsequent requests.
To check the expiry of the token and refresh by creating a request I am using https://github.com/auth0/angular-jwt
I am adding the token refresh code in the config of the app but this method is never called when I make any other requests here is the code which I tried.
app.config(function Config($httpProvider, jwtInterceptorProvider) {
jwtInterceptorProvider.tokenGetter = function(jwtHelper, $http,$localStorage) {
if ($localStorage.currentUser) {
var token = $localStorage.currentUser.token;
if (jwtHelper.isTokenExpired(token)) {
return $http({
url: 'http://backend.mywebsite.com/token',
method: 'GET'
}).then(function(response) {
var token = response.token;
$localStorage.currentUser.token = token;
$http.defaults.headers.common.Authorization = 'Bearer ' + $localStorage.currentUser.token;
return token;
});
} else {
return token;
}
}
}
$httpProvider.interceptors.push('jwtInterceptor');
});
I would like to know how to configure this functionality so that whenever the token expires it is automatically refeshed and set in the http headers?
Points you should consider
You shouldn't change the default headers inside the tokenGetter function.
If your token is expired, you can't call the token endpoint.
You have two options, you can use Refresh tokens and make a post request to a delegation endpoint that makes use of the refresh tokens to obtain a new(not-expired) token.
OR
You can update the JWT with a delegation endpoint and request for a new access token just before the token expires. If the token has expired and there is no refresh_token, you can't really do anything.
A refresh token is a special kind of JWT that is used to authenticate a user without them needing to re-authenticate. It carries the information necessary to obtain a new access token.
In other words, whenever an access token is required to access a specific resource, a client may use a refresh token to get a new access token issued by the authentication server. Common use cases like yours include getting new access tokens after old ones have expired, or getting access to a new resource for the first time. Refresh tokens can also expire but are rather long-lived.
A sample code example for using a refresh token to obtain a new token after a token has expired can be found below:
angular.module('app', ['angular-jwt'])
.config(function Config($httpProvider, jwtInterceptorProvider) {
jwtInterceptorProvider.tokenGetter = function(jwtHelper, $http) {
var jwt = localStorage.getItem('JWT');
var refreshToken = localStorage.getItem('refresh_token');
if (jwtHelper.isTokenExpired(jwt)) {
// This is a promise of a JWT id_token
return $http({
url: '/delegation',
// This will not send the JWT for this call
skipAuthorization: true,
method: 'POST',
refresh_token : refreshToken
}).then(function(response) {
localStorage.setItem('JWT', response.data.jwt);
return jwt;
});
} else {
return jwt;
}
}
$httpProvider.interceptors.push('jwtInterceptor');
})
If you want more information about refresh tokens and how they work, you can check out this article.

Angular HTTP Basic Auth logout header change ignored

I'm using basic HTTP auth (without SSL for testing).
The login works fine, we send an $http request with the authorization header and if the login is correct, it works.
For logout, I'm setting the Authorization header to a bad value and sending an $http request to "trick" the server. The server seems to ignore the new changed auth header. I verified with developer tools in FF that the header value is all ones, but the request is still successful.
How do I "logout"? The logout function sends a bad Authorization header, and the browser sends it according to firebug. What's going on? This is a Java EE 7 app with Wildfly 9 and Shiro, if that makes a difference.
Here is the code:
var DataFactory = function($http, $rootScope, $base64, $cookieStore) {
var _debug = false;
function _d(message) {
if (!_debug) {
return;
}
console.log(message);
}
function setDebug(flag) {
_debug = flag;
}
function doLogout() {
_d("Logging out");
$rootScope.globals = {};
$cookieStore.remove('globals');
$http.defaults.headers.common['Authorization'] = 'Basic 111111111111111111';
$http.get(
'http://localhost:8080/myapp/rest/v1/svc')
.then(function(data) {
alert("Logout: " + JSON.stringify(data.data));
}, function(data) {
alert("Logout Error: " + JSON.stringify(data))
});
}
function doLogin(username, password) {
var token = $base64.encode(username + ":" + password);
_d("Logging " + username + " in with token " + token);
$http.defaults.headers.common['Authorization'] = 'Basic ' + token; // jshint
// ignore:line
$rootScope.globals = {
token : token,
username : username
};
$cookieStore.put("globals", $rootScope.globals);
_d("Login finished, globals are: " + JSON.stringify($rootScope.globals));
$http.get(
'http://localhost:8080/myapp/rest/v1/svc')
.then(function(data) {
alert(JSON.stringify(data.data));
}, function(data) {
alert("Error: " + JSON.stringify(data))
});
}
;
return {
setDebug : setDebug,
doLogin : doLogin,
doLogout : doLogout
};
}
Sending your own authorization string within a XHR request will not magically delete the information cached in the browser. Basic authentication has no concept of logging out. The only way to "logout" with basic authentication is to make the credentials invalid at the server, i.e. change username and/or password so that the stored credentials do not work any longer.

Angularjs: Making another $http request inside a $http interceptor

I have a simple (half finished) http interceptor that appends a Bearer token (stored in $window.sessionsStorage) to the header so that REST API requests can be authenticated:
function accessTokenHttpInterceptor($window, $http) {
// Try to get token details from sessionStorage
var accesstoken=$window.sessionStorage.getItem('userInfo-accesstoken');
var refreshtoken=$window.sessionStorage.getItem('userInfo-refreshtoken');
var tokenexpiry=$window.sessionStorage.getItem('userInfo-tokenexpiry');
return {
request: function($config) {
// Check if the access token, refresh token and expiry date exists:
if (accesstoken == undefined || refreshtoken == undefined || tokenexpiry == undefined) {
console.log('Missing token details');
// TODO REDIRECT TO LOGIN PAGE
}
// We have an access token. Has it expired?
var expiry = new Date($window.sessionStorage['userInfo-tokenexpiry'])
var now = new Date
if (now > expiry ) {
console.log('Token expired');
// TODO REFRESH THE TOKEN
};
// Set the authorization header
$config.headers['Authorization'] = 'Bearer ' + accesstoken;
return $config;
},
};
}
accessTokenHttpInterceptor.$inject=['$window'];
function httpInterceptorRegistry($httpProvider) {
$httpProvider.interceptors.push('accessTokenHttpInterceptor');
}
angular
.module('myApp')
.config(httpInterceptorRegistry)
.factory('accessTokenHttpInterceptor', accessTokenHttpInterceptor)
As you can see, I am able to see if the token has expired prior to making the call to the API.
Can anybody help me with how to refresh the token prior to making the actual API request? I would think that making another $http request would be intercepted again and end up in an infinite loop.
The token is refreshed by making a POST request to the API, where the refresh token is passed as a parameter, not in the Authorization header like other API requests.
You could check the url of the request to prevent an infinite loop. Also instead of returning the config directly you could return a promise that resolves with it so you can wait until you have a valid token. e.g.
{
request: function(config) {
if(config.url != 'my/refresh/url') {
var promiseToHaveValidToken;
var expiry = new Date($window.sessionStorage['userInfo-tokenexpiry']);
var now = new Date();
if (now > expiry ) {
promiseToHaveValidToken = $http.get('my/refresh/url').then(function (response) {
return response.data.token;
});
} else {
promiseToHaveValidToken = $q.resolve(sessionStorage['userInfo-accesstoken']);
}
return promiseToHaveValidToken.then(function (token) {
config.headers['Authorization'] = 'Bearer ' + token;
return config;
});
}
}
}

implementing refresh-tokens with angular and express-jwt

I want to implement the Sliding expiration concept with json web tokens using angular, nodejs and express-jwt. I'm a little confused on how to do this, and am struggling to find any example of refresh tokens or and other material relating to sessions with these technologies/frameworks.
A few options I was thinking of were
Generating a new token with each request after the initial login
Keeping track of issued token on the server side along
But I'm honestly not sure, please help
I managed to implement this scenario.
What I've done...
On the server:
-Enable an API endpoint for signin. This endpoint will respond with the Json Web Token in the header. The client side has to catch it (with $http interceptors) and save it (I use local storage). The client will also manage the refreshed tokens sent by the server.
-On every request to the server configure a middleware in express to validate the token. At first I tried express-jwt module but jsonwebtoken was the right one for me.
For specific routes you may want to disable the middleware. In this case signin and signout.
var jwtCheck = auth.verifyJWT;
jwtCheck.unless = unless;
app.use('/api', jwtCheck.unless({path: [
'/api/auth/signin',
'/api/auth/signout'
]}));
-The middleware verifyJWT always responds with a token in the header. If the token needs to be refreshed a refreshed function is called.
jwtLib is my own library where the code lives to create, refresh and fetch jwt tokens.
function(req, res, next) {
var newToken,
token = jwtLib.fetch(req.headers);
if(token) {
jwt.verify(token, config.jwt.secret, {
secret: config.jwt.secret
}, function(err, decoded) {
if(err) {
return res.status(401).send({
message: 'User token is not valid'
});
}
//Refresh: If the token needs to be refreshed gets the new refreshed token
newToken = jwtLib.refreshToken(decoded);
if(newToken) {
// Set the JWT refreshed token in http header
res.set('Authorization', 'Bearer ' + newToken);
next();
} else {
res.set('Authorization', 'Bearer ' + token);
next();
}
});
} else {
return res.status(401).send({
message: 'User token is not present'
});
}
};
-The refresh function (jwtLib). As argument needs a decoded token, see above that jsonwebtoken resolve a decoded when call to jwt.verify().
If you create during signin a token with an expiration of 4 hours and have a refresh expiration of 1 h (1 * 60 * 60 = 3600 secs) that means that the token will be refreshed if the user has been inactive for 3 hours or more, but not for more than 4 hours, because the verify process would fail in this case (1 hour window of refreshing). This avoids generating a new token on each request, only if the token will expire in this time window.
module.exports.refreshToken = function(decoded) {
var token_exp,
now,
newToken;
token_exp = decoded.exp;
now = moment().unix().valueOf();
if((token_exp - now) < config.jwt.TOKEN_REFRESH_EXPIRATION) {
newToken = this.createToken(decoded.user);
if(newToken) {
return newToken;
}
} else {
return null;
}
};
On the client (Angularjs):
-Enable a client side for login. This calls the server endpoint. I use Http Basic Authentication encoded with base64.
You can use base64 angular module to encode the email:password
Note that on success I do not store the token on the localStorage or Cookie. This will be managed by the http Interceptor.
//Base64 encode Basic Authorization (email:password)
$http.defaults.headers.common.Authorization = 'Basic ' + base64.encode(credentials.email + ':' + credentials.password);
return $http.post('/api/auth/signin', {skipAuthorization: true});
-Configure the http interceptors to send the token to the server on every request and store the token on the response. If a refreshed token is received this one must be stored.
// Config HTTP Interceptors
angular.module('auth').config(['$httpProvider',
function($httpProvider) {
// Set the httpProvider interceptor
$httpProvider.interceptors.push(['$q', '$location', 'localStorageService', 'jwtHelper', '$injector',
function($q, $location, localStorageService, jwtHelper, $injector) {
return {
request: function(config) {
var token = localStorageService.get('authToken');
config.headers = config.headers || {};
if (token && !jwtHelper.isTokenExpired(token)) {
config.headers.Authorization = 'Bearer ' + token;
}
return config;
},
requestError: function(rejection) {
return $q.reject(rejection);
},
response: function(response) {
//JWT Token: If the token is a valid JWT token, new or refreshed, save it in the localStorage
var Authentication = $injector.get('Authentication'),
storagedToken = localStorageService.get('authToken'),
receivedToken = response.headers('Authorization');
if(receivedToken) {
receivedToken = Authentication.fetchJwt(receivedToken);
}
if(receivedToken && !jwtHelper.isTokenExpired(receivedToken) && (storagedToken !== receivedToken)) {
//Save Auth token to local storage
localStorageService.set('authToken', receivedToken);
}
return response;
},
responseError: function(rejection) {
var Authentication = $injector.get('Authentication');
switch (rejection.status) {
case 401:
// Deauthenticate the global user
Authentication.signout();
break;
case 403:
// Add unauthorized behaviour
break;
}
return $q.reject(rejection);
}
};
}
]);
}
]);

Resources