I am writing a REST client in Java using the HttpCLient , the REST API that I access needs an auth token for every REST action. This token is valid for 24 hours.
The way I am handling this now is calling a "getAuth()" method everytime I need to make a REST call which seems like an overhead on the auth server.
How can I conveniently store this auth token and manage its life cycle?
Are there any documented best practices?
I thought of the following solution
public class MySession {
String user;
String pass;
public MySession(String user, String pass) {
this.user = user;
this.pass = pass;
}
public getAuth() {
//user user, pass to get auth token
}
}
and then pass the sessions object to any class that nees the token. If the token is expired, just call this method again
For brevity I'll assuming you're calling an endpoint that you can't change. How you should implement will heavily depend on whether the token is app or user based (one token for all users on a shared app instance or one token per user).
If it's one auth token for the entire app:
Store it in memory along with a time-to-live timestamp (or alternatively catch the token expired error, request a new token and retry the original request), refresh it if it doesn't exist/is expired
If you're concerned about re-requesting API tokens after an application restart also store it in the database and load it at startup if it exists
If it's one token per user:
Store it in your user session, it's exactly what sessions are used for, if you're authing users then they'll have a session and the overhead is already there
If you don't want to re-request a token everytime they login store their current token in the DB and and load it into their session when they login
I'm assuming you are using OAuth for authorization. Whether you are using JWT or other tokens is irrelevant to this situation.
When performing authorization you will be issued an access_token with an expiration and, depending on the grant type you are requesting (Client credentials, Authorization code, Implicit, Resource owner), a refresh_token.
The client should keep the access_token and the expiration. The refresh_token, if issued, must be kept secret (beware of using the correct grant for your use case).
In subsequent calls, your client should not request new tokens on each call, it should use the stored access_token.
Once the API starts returning 401 Unauthorized, the access_token has probably expired. Your client should try to refresh the access_token using the refresh_token if you got one.
If you have no refresh_token or the refresh request also failed, because the refresh_token is no longer valid, you can perform a new authorization flow.
You can use the expiration time as a clue to know when to get a new access_token either through refresh or through a new full authorization flow. This will avoid the 401 Unauthorized. In any case, your client should have a fall back policy when this response is received after having used a valid access_token for some calls.
You can create a manager and store the auth-cookie during login in thread local like the code below. You can get the cookie from getAuth() as long as the thread lives.
public class Manager {
private static final ThreadLocal<String> SECURITY_CONTEXT = new ThreadLocal<>();
public static void setAuth(String auth) {
SECURITY_CONTEXT.set(auth);
}
public static String getAuth() {
return SECURITY_CONTEXT.get();
}
public static void clear(){
SECURITY_CONTEXT.remove();
}
}
I suggest you to use the following scenario:
1) First, call auth(username, password) rest api to get the auth token.
If the given credentials are okay then just send back the auth cookie to the client with HTTP 200 response code.
2) Then, you can call protected rest apis. You need to send auth cookie with your request each time.
3) Servlet filter (or something similar) checks each incoming request and validates the token. If the token is valid then the request goes forward to the rest method, if not you need to generate an http 401/403 response.
I suggest you not to write your own authentication layer. Instead of install and use an existing one. I suggest you OpenAM. It is a superb open source access management system.
I also suggest you not to open session on the server side for authentication purpose. If you have 10 clients then 10 sessions needs to be managed by server. It is not a big issue. But if you have 100 or 1000 or millions different clients than you need more memory to store sessions on the server.
If you are worried about too many hits to the database, then i'm assuming there is a lot of web activity.
I would not recommend using Session in your case, but rather store the token in a cookie on the client.
In a high traffic environment(which i'm assuming yours is), the use of Session can consume a lot of server memory, and scalability can be a concern as well, having to keep sessions in sync within a cluster.
As #Cássio Mazzochi Molin also mentioned, you can use an in-memory cache to store any user specific data and tokens. This will reduce the hits to the database, and also allow you to scale the application easier, when the need arises.
The de-facto standard is not implementing your own solution (basic rule in security: don't implement your own stuff!), but use the de-facto standard solution, namely JSON Web Tokens.
Documentation on the site, but the basic idea is, that you only need to store one value (the server's private key), and then you can verify every claim, issued originally by the server (which will in your case contain an expiry time).
You should use JsonWebToken (JWT in short) for this kind of stuff. JWT has build in support to set the expiration date. There are plenty of libraries to use this method and you can read more here
There are currenlty 4 java implementations and all of them can check if the token is still valid (exp check)
So if I'm understanding correctly you are using the same token for all of your requests (which means as long as your app is up and running and you refreshing the tokens, you should be ok. I literally had the same problem and this is how I've resolved it. I have a singleton class, which is initialized at the app start for once and refreshes the token when its invalidated. I'm using C#, Asp.NET MVC5 and AutoFac for DI, but I'm sure you can do the same with Java and Spring.
Updating property of a singleton with Thread Safety
Use json web tokens , to exchange information between two clients. The token will only alive for the 24 hours period, after that time all consequent calls in the header will be rejected.
Auth Token for each request is correct approach, Consider auth server scaling for performance issue.
On first successful authentication (username and password), generate private public keypair. Store private key as Session Security Token (SST) and send public key as Public Security Client Key (PSCK) to client
In all request other than login (or authentication) client will send PSCK to protect theft of username and password and server can verify PSCK for expiry internally at regular intervals saving processing time.
If system is having performance issue on authentication side, setup seperate auth server with scalability.
No token or password to be cached, exchanged unencrypted and send outside security zone. Do not post using URL parameters.
I am trying to use txtwire (for sending SMS) and they provide a httppost service mentioned below. I know it is "https" but still.. is it OK to pass my API key, userName & Password in the URL?
There is no Basic Auth Mechanism because service expects everything in URL.
https://api.txtwire.com/httppost?phone=18885554433,18885554422&username={username}&password={password}&api_key={api_key}&code=12345&keyword={Group Keyword}&message=testMessage
My only other option is to user their SOAP web service. which is cumbersome and i would prefer RESTful. would SOAP be better if passing credentials in URL is not preferred?
Here is the API : https://api.txtwire.com/documentation/class_w_s___message.html#a99faeee5de80610649b184f180098982
will appreciate any help.
Is it permitted? Well, this is a question that API service provider should answer. It looks like that textWire API doesn't have any issue with it.
For the sake of security, personally, I don't like to post/get credentials without being encrypted. Even with Basic Authorization, there is a way to add encrypted username and password as request header "Authorization". Something similar to the following:
headers['Authorization'] = 'Basic '+ <encoded Base 64 String (username + password)>
Perhaps you want to find out if textWire API support such approach.
You should be ok for both of them, from what I can see they're using an SSL+TLS certificate.
From a more technical point of view, passing the password as part of the query string (RESTful), passing it in the request body (SOAP) or passing it as a request header is actually the same approach (don't forget that basic authentication trasmits the credentials as username:password sequence encoded with base64), because the password itself is being transmitted along with the message itself.
It's a possibile practice, but I would not raccomend it. If I were to expose an authenticated service I would use a username+HMAC signature combination, or maybe an autentication token of some sort.
I have a small REST-ful Java back-end that some clients written in C connect to. There is a certain POST method they call where they send some information, I save that to a database and respond with 200 OK, if all goes well. Basic structure shown below.
#POST
#Path("/mypath")
#Produces("text/html")
public Response processMessage(final String message, #Context final HttpServletRequest request) throws IOException {
.....
return Response.ok().build();
}
My issue is that on this response, I get the following error in the log:
javax.ws.rs.NotAllowedException: No resource method found for , return 405 with Allow header
I understand what this error means in circumstances when let's say you try to execute a GET on an endpoint that is supposed to be a POST, for example. I can't understand though why I would get this after my response goes out, and it clearly shows that the request type is empty.... so odd.
Some additional info - the code on the client side has been buggy with incorrect HTTP code... but what would have to be wrong on the client side to cause this kind of response? (I do not have access to the client side code).
Also, there is no client side code in my app, if you are wondering if there is some other code making a call out of my webapp.
Thanks for any ideas!
The issue is most likely on the client side, so without seeing that code it is difficult to offer more detailed information -- but my expectation would be that this is a result of your client attempting to do something like POST or PUT credentials, or something along that line.
Your only recourse is to enable verbose request logging, log the requests that are generating 405 errors, and report it to the client developers.
Worth noting, however, that any publicly-exposed APIs will generate piles of 405s and 404s because "hackers" will try to execute things like WordPress hacks and so on against any known URL.
When I send a request using a proxy client, if I get a certain response, I would like to be able to modify the request and then send the same request again for all requests.
Normally I would do something like:
BookStore proxy = JAXRSClientFactory.create("http://books", BookStore.class);
try
{
proxy.getBook("someId");
}
catch(WebApplicationException ex)
{
Response r = ex.getResponse();
if (r.getStatusCode() == 404)
{
proxy.getBook("anotherId");
}
}
But in this case, there is a common thing I want to do for all requests: If I get a specific http code, modify some header values, and then try again (probably with a limit on the amount of retries).
I haven't seen a way that cxf proxy clients explicitly support this, how could I go about implementing it?
You need to write an interceptor to do this for every request.
here you go for sample code and documentation http://cxf.apache.org/docs/jax-rs-filters.html
I'm implementing an android app and I'm having trouble understanding how I can implement a login feature (very simple, no encryption needed) and how it works after the user logs in
So, the first thing to do is make a Request, I send the login, and password,with an http POST method probably?
and the server replies with a token of some sort, correct?
Then I save that token, and what happens next? I have a bunch of pages I need to make GET requests on, but I also need to send the token someway, right?
How exactly can I make that?
thank you
You pretty much have it summed up I guess. Let the app send the credentials with a POST, the server checks if they are okay, then sends back a token (some random String maybe). When you make the GET requests after login, send the token with a custom HTTP header and let the server check it. The server has a list of valid tokens and checks if the received token is valid. If not, it responds with an error message, else it does what it's supposed to do.
That's all very basic and not at all secure of course.
Edit: The GET request could be done like this:
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet("someUrl.com/rest");
get.setHeader("Authorization", "someTokenYouCreated");
HttpResponse response = client.execute(get);
You'll find lot's of examples about calling a REST method. You'll have to look up how to handle that header on the server side, but that can't be too difficult either.