I am trying to understand statelessness in restful APIs in the context of authentication. Here's the scenario:
The user logs in.
The server verifies the username and the password, and generates an opaque access token. It caches some information related to this token - for example, the expiration time, the userId, whether this token was explicitly invalidated before it expired, etc.
The token is sent to the client, and the client sends it with every future request.
List item
Fielding's dissertation defines statelessness as:
"...such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client."
In my example, the client is sending the token with every request, so the first condition is satisfied. However, my server has a context associated with this session that is stored in the sessions cache.
Does this make my application stateful?
If yes, then is it that true statelessness be achieved only if we are using JWTs? I am pondering upon this as JWTs are quite new, so how were architects building truly stateless services before they were invented?
That's right. If you you maintaining the session you are keeping the state in server which makes the application hard to scale. True stateless applications can be scaled out and any server should be able to handle the request.
JWT is popular way to avoid sessions and everything is encapsulated inside the token for any server to auth/Authorize the request and help us achieve stateless application, they come with their own challenges however OpenID connect is the new way for Auth/Authorization.
Before jwt to make application stateless we used to keep session in DB (or Shared Cache) , and any server would like to check the session would have to contact DB.
Hope that Helps!
Briefly: No, such usage of token does not make your application stateful.
Detailed: When we talk about stateless/stateful, we consider usually only the data that affect business logic. Business logic does not usually depend on authentication data. For example, a user sends a request that contains all data needed to place some order. Normally creating an order does not depend on when this user has logged in, on his user ID, etc.
Related
When a user is authenticated by the server, the server sends, according to the most common implementation I found(which is were my question stems from), sends BOTH access token and the refresh token to the client.
-- My first questions is:
What is the point of sending both tokens to the client if, to my understanding, we have the refresh token in the first place to help us mitigate the consequences of an access token being leaked?
If both tokens are sent to the client and are stored together (in the same place, localStorage, sessionStorage, one in former, one in latter - I don't think it matters to the questions how we decide to store them on the client), if an attacker manages to steal the access token, then it is safe to assume he would also find a way to steal the refresh token from the same client since they are most likely stored together. I don't understand why most implementations and answers I find online mention sending both tokens to the client since its basically like putting all eggs in the same basket.
(A big part of my confusion comes also from the fact that those answers and implementations don't mention anything about storing the tokens in HttpOnly cookies, which I'd think would be a common practice if we want to prevent tokens getting leaked, so I'm getting a feeling I'm missing something)
-- My second question would be:
Would it be a correct solution then to persist the access and refresh tokens upon issue in an "accessT <-> refreshT"(like a key=value pair) table on a server, so that only one token is ever sent to the client - the access token? And when that access token expires the process of "refreshing" would be the following:
ResServer = resource server
AuthServer = authorization server
The request with the expired token is sent to the ResServer.
ResServer checks and sees that the access token has expired.
ResServer then sends a request to the AuthServer to look up the refresh token by the access token in the table mention above.
If AuthServer finds a refresh token by using the expired access token as a key - good, AuthServer generates a new access token.
AuthServer then responds to the ResServer with that new access token.
Having received a positive response, ResServer proceeds on with it's usual flow for authorized users.
^^ This seems to me to be a more rational way of keeping the refresh token safe - making it serve its primary function, which is why I don't understand why most other implementations on the web always mention sending both tokens to the client.
-- And my third question is:
Not having much experience implementing microservices, I am confused about why we would ever prefer to implement this token back and forth approach, when, from what I understand, the entire point of tokens is that they are supposed to be a stateless solution(well, the refresh token is always kept on the server regardless of implementation, which confuses me even more about that "stateless" part). Doesn't it make more sense to just use cookies that basically serve the same function, but are easier to implement, secure by default("Secure", "HttpOnly" flags), and, as it appears to me, are much easier to revoke in can they are leaked?
Thanks you for taking your time to read this entire post, I appreciate your help.
Regarding your first question:
The advantage of having two tokens is not that you can store one of the tokens more securely. The advantage is that if the Resource Server gets compromised, it does not allow lateral escalation. For this to make sense, your access tokens must be bound to specific resource servers.
As an example, assume you have two resource servers ResA and ResB. Then your Authentication server would allow you to obtain one access token for each of these servers, and one refresh token (that allows refreshing both access tokens). If resource server A gets compromised (or the network path between the client and that server), then the access token to that server will expire at some point, and the attacker will not be able to access resource server B with the access token issued for resource server A. At the same time, only the legitimate user is able to refresh their tokens, since they only provide the refresh token to the AuthServer, such that a compromised or malicious resource server never sees at.
That leads directly to your second question:
Your proposed model prevents key rollover. If a resource server gets compromised, all its tokens are eternally compromised, unless the Authentication Server voids all refresh tokens. Voiding refresh tokens would lead to users being logged out of all resource servers (even those who are not compromised).
As an example, consider the following scenario: Tour authentication provider is a large public service, such as "Sign in with Google", with thousands of resource servers using this service. Now one of those resource servers gets compromised, and attackers steal the authentication tokens.
In the commonly employed auth-refresh token pattern, the auth tokens will expire, which means that the service will be inaccessible for attackers as soon as the used vulnerability is fixed + the time it takes for tokens to expire (since the attackers could not get hold of the resource tokens), without the need for the AuthServer to do anything. Additionally, the AuthServer does not need to keep track of the issued tokens, if it uses cryptography to sign the tokens with a private key only known to the auth server, as it (and all resource servers) can trivially verify token authenticity by validating against a public key (please also see the end of my answer).
In your proposed approach, the AuthServer (which is Google in this example) would have to void all refresh tokens OR they would have to selectively delete all auth-refresh token pairs for the affected resource server from the key-value store. That key-value store will be gigantic, since it has to contain EVERY auth token ever issued, for any service that uses "Sign in with Google", and apart from storage costs, this delete operation will take quite some time.
Regarding your last question:
You can store access tokens in Cookies. There is a bunch of advantages to that (including the Secure and HttpOnly flags that you mentioned). It has two disadvantages: If you want to implement something like a CLI client that runs outside of a browser, you would have to implement Cookie handling. The other disadvantage is the CSRF risk as Cookies are automatically sent on every request. Using local storage prevents this, as an external website cannot access the local storage of your website to extract the token.
In the end it comes down to the concrete scenario, if Cookies or Local Storage + Custom Header are the preferable solution.
However, I think you have a misconception regarding statefulness:
Access and Refresh tokens do not need to be stored on the server. Instead, the Auth Server signs the Token Contents with a cryptographic private key, before sending them to a client. In doing so, the AuthServer includes an expiration date in the token, which is included in the signed content.
To validate the token, the Resource Server (or the AuthServer) checks if the signature comes from the AuthServer's private key, and then checks if the expiration date has passed. In particular, the resource server does not need to communicate with the AuthServer, apart from obtaining its Public Key from time to time. This makes this solution scale really well for very large deployments. See the Microsoft Azure docs, which do a great job on explaining the difference between Auth and Refresh tokens.
What you are alluding to are traditional session ids, which are stored on the server until they expire. Thats obviously a much simpler solution, and works well for smaller, more monolithic applications. It just does not work for hyper scalers.
I am using play framework to develop a web app. Now I need to implement authentication/authorisation without database (really strange requirement). There will only be log in and log out function, no registration. The username/password pair will be authenticated using external service.
Due to limited experience, my current idea is to use token to authenticate and a local file to store username/password.
Is my idea feasible? Is there any recommended libs? If I use token, do I need to pass that token in Http request/response every time and authenticate the token in every controller?
Thanks!
Why store user name and passwords in a local file? I don't see the point and this constitutes a database, which you want to avoid it seems... Deciding to work with local files will be an important limitation if you ever want to deploy more than one server and have some load-balancing done.
Playframework is stateless, meaning that the server doesn't keep session state. To work around that play uses signed session cookies (the browser is storing the session data, and cannot modify it as the session data is signed).
Here's what you can do:
on login: set some data in the session
on each subsequent request, determine the state (logged-in or not) based on the session cookie, see https://www.playframework.com/documentation/2.6.x/ScalaActionsComposition#Authentication
on logout: reset the session cookie
Now this approach has a serious downside, it allows people to replay (reuse) old session cookies to pretend being logged. Another (could be less serious depending on your requirements) is that it is not straightforward to implement session expiration after a certain inactivity.
This is probably enough to answer your question and give you a starting point.
A server provides a JWT to the client during authentication. That JWT contains information which is then later used by the server. For example, JWT may contain permissions array with the list of all permissions granted to a specific user.
Is it considered bad practice, if client parses the JWT and uses the permissions information contained within it? Is it better for client to make additional call to server (GET /permissions, for example) and behave according to that response?
This will strongly depend on a lot of small details; I'll try not to forget anything, but in theory it should be fine to do so and if certain conditions are met I would not consider it a bad practice.
OAuth2 states that access tokens should be opaque to clients, but JWT is just a token format (Learn JSON Web Tokens) and it's usage in other circumstances does not imply the same rules as OAuth2.
Also note that getting the information from an additional request has the same end result with the additional overhead of one more call. There would be a slight benefit if permissions are very volatile given you could repeat the calls.
However, the important part is more focused on what you mean by the client and how would the client use that information so I'll elaborate on this.
Assumptions:
the client you mention can be deployed as browser-based application (SPA's), native application or be some server-side component acting as a client.
both the server and client are controlled by the same entity.
the client and server components can be seen as a single application, that is, for an end-user the fact there's client and server components makes no difference; they use them as a whole.
Explanation
In this situation the token issued by the server is just a way for the client to later access protected resources without requiring explicit user authentication again; it's a mechanism to maintain a session between the two components.
Given the same entity controls both the client and server, it's acceptable to treat the received token as a whitebox instead of a blackbox. The client can then interpret the information in the token and take advantage of it to provide a better experience for the end-user. However, this implies that the server will need to continue to validate the token and it's permissions accordingly; any interpretation of the data by the client is purely to provide optional functionality.
Furthermore, for clients deployed to hostile environments like it would be the case for a SPA application the decisions taken by looking into the data must only result in purely aesthetic decisions, as the user could fake the permissions data. For example, you could use it to conditionally hide/disable some user interface just so that the user wouldn't have to click it to find out it wasn't allowed to do so.
A good analogy would be Javascript based input validation in web forms; you should do it for better user experience, but the server will need to do it again because the user can bypass the Javascript validation.
I have started to design a RESTful API and I'm thinking about how to handle authentication. I want to use some kind of authentication token but I can't use OAuth o similar infrastructures so I have to handle it myself.
One of the requirements for this API is that it must have good performance, enough to handle a high volume of requests before there is the need to scale; my concern is how to make on each request the time needed to verify the token (integrity, expiration, IP Address, etc...) as little as possibile.
I suppose the token should some kind of hash and not an encrypted string containing the user information because the decryption time would be to heavy.
I've read that I could store the tokens in an in-memory hashtable where the key is the token and the value is the user info needed to process the request, but how can I make this work in a clustered environment where there will be an hashtable on each "node"?
Should I put tokens on a DB table an hit the DB every time also Handling manually the retention of expired tickets?
Probably it's not that important for the question but I'm using Spring MVC for the RESTfull API.
Thanks in advance.
I solved my problem by using both an in-memory cache and a db cache. Here is a summary of my solution that may help anyone with the same task.
the user logs in and in that moment a unique key is generated and sent back to the user.
that login token (which is basically a GUID with some processing) is also store in a db table with additional info like exipiration and with the user's info and roles. the same pieces of information are also store in memory (google guava hashtable where the token is the key)
the token must be passed along with every api call in the authorization token as #ipa suggested
the server code checks if the token is in its memory cache the user info are already available otherwise (e.g. the api call is done on another node in the cluster) the token is search in the token db
once the token is found you can check expiration, roles, etc...
This grants a good level of performance and security, the token can be generated with any arbitrary algorithm even a relative slow one since you don't have to recalculate it on every api call. Also this works with a stateless service wich can be scaled up horizontally.
I assume you use https and therefore all the traffic is encrypted. I'd suggest one of the following principles.
Basic Authentication
You can add the credentials in the Authorization header of the request. This credentials are encoded with Base64 (see below). This credentials could be sent on every request and then checked with your DB. To get this faster and less IO intensive you can still use a cache. Once I implemented an API like this without a cache and was able to handle thousands of requests per second.
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Authorization Token
There are different ways to implement your idea with a token. A common one is that every API user has his own token usually called api key which never expires. Another one is that you first have to authorize (Basic Authentication) and then get a token back which expires. This one is then used as api key for a certain time.
Either way you have to decide whether to use a cache or not. I would keep it simple and go for basic authentication and check the db every time. Almost every framework has very good support for this approach because it's simple http. If this causes performance issues (I'd recommend performance tests anyway) try to add the table with your credentials to the JPA cache. If you want to implement something with expiring tokens have a look at Infinispan.
You can store token in Redis. If you are going to store it in DB, make sure you optimise server (if you are managing it) for read operations. I have couple of implementation where folks have used key value store as well. Hashtable is also good idea.
I have built a simple test API for a CakePHP application that will let a user login from a mobile device (or any device for that matter) and get a JSON response. This API could be used for a mobile app built in PhoneGap.
The login method looks like so:
public function login()
{
if($this->request->is('post'))
{
// Use custom method in Model to find record with password params
$findUser = $this->User->findUser(
$_POST['username_or_email'],
AuthComponent::password($_POST['password'])
);
// If a user exists and matches params
if($findUser)
{
$this->User->id = $findUser['User']['id'];
$this->autoRender = false;
$this->response->type('json');
$this->response->body(json_encode(array('authenticated'=>true,'message'=>__('You have been logged in successfully'))));
}
else
{
$this->autoRender = false;
$this->response->type('json');
$this->response->body(json_encode(array('authenticated'=>false,'message'=>__('Username or password is incorrect'))));
}
}
else
{
$this->autoRender = false;
$this->response->type('json');
$this->response->body(json_encode(array('message'=>'GET request not allowed!')));
}
}
The mobile device (or any API user) can send their login details and then they get the request as JSON as true or false for authenticated. This boolean is NOT used to give the user access, it instead tells the mobile app if they can see certain screens and they ONLY get the data or can send data if the session exists!
As just stated, they are also actually logged into the API itself on the device so if they visit the website directly (from that device) they will have a session and see the same response for the JSON.
So essentially a user remains logged in for the duration of the session on the device they communicated with the server on. This is different to a token which would need to be passed for every request, where as in this example they have a session.
Now the questions...
Is it bad practice for the user to be 'actually' logged into the API
with a session like shown above? It seems like the most secure way to handle authentication for a device as it's using the same logic as the direct web root.
I've seen some APIs use access tokens instead which I've also
implemented (user gets their token returned instead of the boolean
and no session is created). But from what I can tell, this seems
like more work as then I need to check for the access token against
a user record every time a request is made.
edit
For the sake of clarity, I am not a supporter of REST, I AM a supporter of RESTful/RESTlike services. If you look at all of the API's on the internet, very few actually stick to one standard. Whatever scheme you choose will depend on your specific problem-space. Just try to be secure and use intuitive design choices (ie dont name a service "cats" if it returns info about "dogs")
end edit
It is good practice in RESTful API's to manage some form of session/tokenizing scheme. Really the ideal (at least in my opinion, there are many schools of thought on this problem) setup involves rolling tokens.
If you are at all concerned with the security of your API, then permissions should be managed out of your database layer. Yes, this creates a bottleneck, BUT THAT IS ACTUALLY A GOOD THING. Needing to hit the database every single time to validate a client's token adds an extra step in the entire process. This slows down the API, which is actually desireable in a secure system. You don't want a malicious individual to be able to hit your API 3000 times a second, you want their requests to hang for a (somewhat) sizeable fraction of a second.
This is similar to MD5 hashing algorithms. Many of them recalculate the hash a few hundred times, with random pauses in between. This helps to keep a malicious client from attempting to brute force a password (by making it take more time to test each variation of the password string). The same applies to your API.
The other benefit, is that if you DO have a malicious user trying to log in over and over again, if you are managing them from the database layer, then you can red flag their IP Address/username/what-have-you and just drop their requests at step 1.
Anyway, for a suggested process (with rolling tokens, you can cut out parts of this if it seems overkill, but this is hella secure):
User hits a 'login' service, this requires a username/password, and returns two tokens, a Private Access Token and a Public Request Token (the server stores these tokens in the db).
The client stores these Tokens in a secure place
User accesses another endpoint to push/pull some data
Request includes a timestamp
Request includes the Public Request Token
Request includes an Access Token=> This token should be a MD5 hash of the string resulting from concatenating the timestamp string to the end of the Private Access Token string
The server takes the Public Request Token, uses that to lookup the Private Access Token that was stored
The server takes that Private Access Token, and concatenates on the Timestamp String, it then takes the MD5 of this string
If the new Access Token matches the one that the client sent the server, HURRAY, this client is validated, so push/pull the data
(Optional) The server generates new tokens on every request, and returns them to the client. This way every transaction invalidates the old tokens, and if there was some kind of man-in-the-middle attack occurring, if the VALID user has already completed their request, the malicious user now has invalid tokens and can't start messing with your API. This scheme tries to ensure that a malicious user can not expect to intercept a single communication between the server and the client, and still gain access to the system. If they do, then the REAL user should immediately get invalidated tokens. Which should then trigger their API client to hit the 'login' service AGAIN, getting new valid tokens. This once again kicks the malicious user out of the system.
This scheme is not 100% secure, no user access system ever will be. It can be made more secure by adding expiration dates on tokens. This scheme also has the added benefit that you can assign specific permissions to users/tokens (ie Read-Only access, only certain End-Points can be seen, etc)
This is not the only way you can do things, I would look up other Authentication Schemes and take what you want from each of them (OAUTH is a good place to start, then I'd look at Facebook/Twitter/Instagram)
Make your app login everytime, but not with login-pass pair as Swayok lastly suggested. When you login, server generates a token and returns it back to the client. Client then uses this token whenever it makes a request. On each request, server checks whether the token is valid and if so, executes the request.
This is very similar to how sessions work in that, server side frameworks manage it internally and these tokens expire from time to time. However, as Swayok rightuflly pointed out, you don't want session mainly because you're RESTful API should have no state. You get the same utility without storing any user specific data regarding user and logging user in with every request.
Here's a good article on this, or you can try the Facebook Graph API explorer to see it in action
Restful API restricts using sessions and saving system state at all. Each request must log-in user.
Access tokes are great but also require additional handling.
The easiest way is to send authorisation data via HTTP Basic Auth ("Authorization" HTTP header)
http://www.httpwatch.com/httpgallery/authentication/
Mobile Applications can easily do that and it is easy to add this header for each request to API.
On server side:
$username = env('PHP_AUTH_USER');
$password = env('PHP_AUTH_PW');
And process user log-in with this data in ApiAppController->beforeFilter()
To answer your questions
Its not a bad practice as long as you close their session on app close and recreate it when needed. it is same as if they were logged in on a browser they would know and have facility to log out however the same should be available on the app as well otherwise they might have closed the app but not actually ended their session. You can handle this in many ways by asking them to log out automatic checking when they close app
Tokens are an enhanced way of doing the above however you have to consider how secure the token is when transmitted and server need to verify the token on each request. You have said that it seems like more work so yes its more work and if you have time or money constrains and looking for an answer to say if the session style would harm your application in future it wont as long as you are in control of session and not leaving user without ending the session. If you have time then implement tokens and you would like that.