I'm looking at retro-fitting JWT stateless authentication to an existing web application.
I'm considering using single-use tokens as well as setting an expiry time. The server will return a fresh token with each response.
My questions are:
How can I automatically append the additional header to every request? It needs to go with every request so that new one can be issued.
Would it be correct to return the new token in the response header and not the body?
I try to answer you. I used jwt saving it in cookies, I put you here a very interesting link, I hope you can help Where store JWT
If you want to put in every request you must write a wrapper around Jquery.ajax or XMLHttpRequest
Related
I'm creating an app using Angular 1.5.8 and Laravel 5.2. I'm using a library by Luca Degasperi to create Token Based Auth
Via Angular I make a call and I receive access_token, TTL and refresh_token. I store access_token and refresh_token on localStorage. I can use access_token that I get to make calls to get some data from my API. When token expires I'm getting a message that the token is invalid with 401 code
So my question is how to check if the token is still valid before I send a http request to my API? What is the best way to refresh the token? Ok, I can send a request for the refresh my token to https://my.api/oauth?grant_type=refresh_token&refresh_token=f32j93201h00xpaf1, but how to check it before every http request? Can I repeat the call if the response code is 401? And how?
Please, give me some advice :)
I had exactly the same problem few days ago. Angular Error response interceptor is all you need ;) Also, this article was really helpful
You cannot. You have to check against a login. Therefore it's just a re-login.
I guess that if you get a 401, your refresh token is already done.
Though I guess that you can join that refresh token with all your requests? I might be wrong.
Ensure that your token TTL is always up to date by refreshing its TTL from time to time (like with requests to your API).
Can't you use the TTL to determine if the token is still active? When you store your tokens in local storage you can add the date/time the token was stored and each time you go to make a service call you can check the TTL against the time the token was stored.
It will only tell you when it expires, though, and not if the token was invalidated for some other reason.
I am having a bit trouble understanding the following code
run.$inject = ['$http'];
function run($http) {
$http.defaults.xsrfHeaderName = 'X-CSRFToken';
$http.defaults.xsrfCookieName = 'csrftoken';
}
as I always thought that csrf is injected into html forms or ajax calls and not cookie, since csrf is a protection against any adversary trying to use your cookie for authentication.
Can someone give a detail explanation on how angular is handling csrf and how does it get the token from the backend?
I can't answer this better than the angular docs themselves do, so I'll just quote:
Cross Site Request Forgery (XSRF) Protection
XSRF is a technique by which an unauthorized site can gain your user's private data.
Angular provides a mechanism to counter XSRF. When performing XHR
requests, the $http service reads a token from a cookie (by default,
XSRF-TOKEN) and sets it as an HTTP header (X-XSRF-TOKEN). Since only
JavaScript that runs on your domain could read the cookie, your server
can be assured that the XHR came from JavaScript running on your
domain. The header will not be set for cross-domain requests.
To take advantage of this, your server needs to set a token in a
JavaScript readable session cookie called XSRF-TOKEN on the first HTTP
GET request. On subsequent XHR requests the server can verify that the
cookie matches X-XSRF-TOKEN HTTP header, and therefore be sure that
only JavaScript running on your domain could have sent the request.
The token must be unique for each user and must be verifiable by the
server (to prevent the JavaScript from making up its own tokens). We
recommend that the token is a digest of your site's authentication
cookie with a salt for added security.
The name of the headers can be specified using the xsrfHeaderName and
xsrfCookieName properties of either $httpProvider.defaults at
config-time, $http.defaults at run-time, or the per-request config
object.
The $http.defaults.xsrfCookieName is just allowing you to specify what the name of the cookie is, otherwise it's going to look for the default XSRF-TOKEN.
On the server side implementation, I'd recommend using some node.js middleware to handle the setting of the initial cookie instead of rolling your own. Take a look at csurf in particular as it seems to be the most popular. You could also try senchalab's csrf middleware. Either of those ought to be enough to get you started.
I know this has been asked countless times, but none of the answers I found described the actual connection to backend.
I have a one-page JS app that communicates with small backend (Django) API. I use session based authentication. User info is cached on first load. If session expires, I need to change page header and flush user info from cache. However, most of my API resources are public and return always 200. Several other resources are private and return 403 if user isn't logged in, which is great as this gives me excatly the information I need. The problem is, some pages access public resources only. In case session is suddenly deleted on backend and user navigates to url that accesses only public resources, user info isn't flushed and I have an UX problem.
My initial idea was to request private user resource (let's call it /users/self/) on every url change which returns 200 in case user is authenticated and 403 in case they aren't. This however requires 1 extra request before every other request for each url change, which isn't really ideal.
Are there any easier techniques I could use in this case? I don't mind even switching to other type of authentication if that would solve the problem.
What i have done and seen for such scenarios is to use some type of http interceptor that intercept all http requests done by Angular and if it finds a response status of 401, such interceptors raise an event using $rootScope.
See one library here https://github.com/witoldsz/angular-http-auth
To use it, one needs to subscribe to the events raise using some type of root controller, which can redirect the user to login page.
See an example here https://medium.com/opinionated-angularjs/7bbf0346acec
Instead of sending a additional auth request, just check in your backend in every request, if the session didnt expire. If the user is not auth, then return a status code.
In angularjs we used a httpResponse interceptor, who intercepts every response and checks against this status code.
Your backend could add a header to the response if the user is still logged in, regardless if the requested resource is public or not. The client can then check the presence of that header and act accordingly.
On both sides this is done with some kind of filter or interceptor. In angular this would be a $http interceptor.
We at work do what others have already told you: use an HttpInterceptor.
We have every response sent from our backend structured in the same way: an object with two fields: a responseCode and the actual response. We vary the responseCode according to what happened in the backend, being success, security alert, or authentication required for that given action the most common cases.
Then the interceptor reacts in the appropriate way according to each responseCode we have defined. In the case of an authentication required, we redirect to the login page, you could do whatever you need. It's working great for us.
I am currently in the process of implementing a server-side OAuth2 flow in order to authorize my application.
The JS application will be displaying YouTube Analytics data on behalf of a registered CMS account to an end user (who own's a channel partnered with the CMS account). As a result of this, the authorization stage needs to be completely hidden from the user. I am attempting to authorize once, then use the 'permanent' authorization code to retrieve access tokens as and when they're needed.
I am able to successfully authorize, and retrieve an access code. The problem begins when i attempt to exchange the access code for a token.
The HTTP POST Request to achieve this needs to look like this...
POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=8819981768.apps.googleusercontent.com&
client_secret={client_secret}&
redirect_uri=https://oauth2-login-demo.appspot.com/code&
grant_type=authorization_code
I am using this code to achieve this:
var myPOSTRequest = new XMLHttpRequest();
myPOSTRequest.open('POST', 'https://accounts.google.com/o/oauth2/token', true);
myPOSTRequest.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
myPOSTRequest.send('code=' + myAuthCode + '&redirect_uri=http%3A%2F%2Flocalhost%2FCMSAuth3.html&client_id=626544306690-kn5m3vu0dcgb17au6m6pmr4giluf1cle.apps.googleusercontent.com&scope=&client_secret={my_client_secret}&grant_type=authorization_code');
I can successfully get a 200 OK response to this Request however no access token is returned, and myPOSTRequest.responseText returns an empty string.
I have played with Google's OAuth Playground - and can successfully get a token using my own credentials.
Am i missing something here?
You cannot do this, because there is the same origin policy. This is a security concept of modern browsers, which prevents javascript to get responses from another origin, than your site. This is an important concept, because it gives you the ability, to protect you against CSRF. So don't use the code authorization flow, use instead the token authorization flow.
Try and build up the full URL. Then dump it in a webbrowser. If its corect you will get the json back. You have the corect format.
https://accounts.google.com/o/oauth2/token?code=<myAuthCode>&redirect_uri=<FromGoogleAPIS>&client_id=<clientID>&client_secret={my_client_secret}&grant_type=authorization_code
Other things to check:
Make sure that you are using the same redirect_uri that is set up in google apis.
How are you getting the Authcode back? If you are riping it from the title of the page i have had issues with it not returning the full authcode in the title try checking the body of the page. This doesnt happen all the time. I just ocationally.
I am interested in how you would determine using XMLHttpRequest if the user had already authenticated with a server? I can send my request and return data but if I refresh the page and request the data again my logon form is firing even though the session time out has not expired.
Any thoughts?
Thanks
Chris
There are a couple options here. Often times a serve will respond with a login form to any unauthenticated request. Thus, if you're making an AJAX request that fetches JSON, you can just look at the content-type of the response, ala xhr.getResponseHeader('Content-Type'). Authenticated responses should be something like application/json, while unauthenticated responses will be text/html (or something like that.)
But... you can also look at document.cookie to see if the user has a session cookie defined. While this isn't a bullet-proof check (the cookie may be invalid, or the server may have additional checks in place that could still fail the request), it's not an unreasonable check to do.