40

On my Java EE6, REST service, I want to use authentication tokens for login from mobile devices, User will send their username, password and server will send back a token, which will be used to authorize the user on their further requests for a given time.

Can I simply create a token myself like this?(I guess I do not need to encrypt this since I will use HTTPS.)

String token = UUID.randomUUID().toString().toUpperCase() 
            + "|" + "userid" + "|"
            + cal.getTimeInMillis();

Or there is a more standard way to create these tokens? maybe it exists in one of the API`s?

zmerr
  • 534
  • 3
  • 18
Spring
  • 11,333
  • 29
  • 116
  • 185
  • 2
    Your current token structure is highly spoofable. If there a particular reason why you don't want to use a proven security library like Shiro or Seam Security? – Perception Dec 21 '12 at 16:17
  • @Perception tnx I dont know any of those, they are for creating tokens? – Spring Dec 21 '12 at 16:20
  • 1
    The point that everyone is trying to make to you in various ways is that writing your own security framework will either be 1) rather difficult or 2) not very secure. Use a proven solution unless you don't really care about security, in which case, why are you even messing with it at all? – Ryan Stewart Dec 21 '12 at 16:21
  • 1
    @Ryan Stewart tnx I updated the question – Spring Dec 21 '12 at 16:28

7 Answers7

48

For Java 8 and above the fastest and simplest solution would be:

private static final SecureRandom secureRandom = new SecureRandom(); //threadsafe
private static final Base64.Encoder base64Encoder = Base64.getUrlEncoder(); //threadsafe

public static String generateNewToken() {
    byte[] randomBytes = new byte[24];
    secureRandom.nextBytes(randomBytes);
    return base64Encoder.encodeToString(randomBytes);
}

Output example:

wrYl_zl_8dLXaZul7GcfpqmDqr7jEnli
7or_zct_ETxJnOa4ddaEzftNXbuvNSB-
CkZss7TdsTVHRHfqBMq_HqQUxBGCTgWj
8loHzi27gJTO1xTqTd9SkJGYP8rYlNQn

Above code will generate random string in base64 encoding with 32 chars. In Base64 encoding every char encodes 6 bits of the data. So for 24 bytes from the above example you get the 32 chars. You can change the length of the output string by changing the number of random bytes. This solution is more secure than UUID (that uses only 16 random bytes) and generates string that safely could be used in HTTP urls.

Dmitriy Dumanskiy
  • 11,657
  • 9
  • 37
  • 57
18

To create a hard to guess token in Java use java.security.SecureRandom

E.g.

SecureRandom random = new SecureRandom();
byte bytes[] = new byte[20];
random.nextBytes(bytes);
String token = bytes.toString();

Rather than including the user name in the token it would be better to cache a user:token map in memory or in a database.  

Alex Weitz
  • 3,199
  • 4
  • 34
  • 57
Daniel de Zwaan
  • 3,064
  • 25
  • 24
  • 5
    Using an array of bytes and `toString` method on an array to generate a token might not be a good solution as explained [here](http://stackoverflow.com/a/1536365/5078385). Actually, you can find a much better solution [here](http://stackoverflow.com/a/41156/5078385). – acm Nov 02 '16 at 10:53
  • 2
    You should not use `toString()` to convert the byte token to string. The non printable bytes will be lost and as a result the token length will be inconsistent. Use Hex, Base64 or similar encoding to convert to printable string. – Nayan Nov 06 '18 at 10:21
9

The scheme you are proposing effectively allows a client unlimited access to your service. After an initial login, the UID and 'userid' will be made available to the client, which can be simply combined with an always valid timestamp.

If you need a service with 'login' and a session token, then why not just use an HttpSession?

ireddick
  • 8,008
  • 2
  • 23
  • 21
  • @Spring You haven't actually stated what your using to publish your REST service (I'd assume jax-rs), so it's hard to give an answer. Maybe ask/research another question? – ireddick Dec 21 '12 at 20:25
  • I created another question, http://stackoverflow.com/questions/13997040/jersey-how-to-intercept-request-for-authentication – Spring Dec 21 '12 at 20:52
1

There is a way to create tokens which is cannot compromised but can be used for authentication too.

Create a token which is combined:

base64(username + expiration + other values for client + 3des encoded(usename, expiration, source ip, browser identitifier, other values for client))

The client can use the token to authenticate the request, for example the usage of JSON Web Token (RFC 7515).

On server side the keys which is used for 3des encoding can be rotated with time, as the token. Every request contains token for authentication and every response contains the same token or a new one before the expiration.

In that case token contains user name so on request authentication only have to check the 3des encoded part is valid or not (same as the , the source of request ip is same. In this case if somebody stole the token the usability of token is more limited as a session id. You can compose other identifiers to token, like browser etc. Harder to fake request, because the attacker have to fake more things - which is unknown for him, because he doesn't know what is on encoded part of token. (As a matter of fact there is no perfect security, only can make harder to crack)

The pros of this solution are:

  • Every piece is standard, but not the whole together and the attacker have to know the implementation details to be able to attack.
  • The client side can use parts of the token for displaying information from token while the token itself is secured because every unencrypted part is contained in encrypted part - so cannot be modified without the invalidation of token on the server side - so its easy to detect an attack.
  • There is no need of session replication / sticky sessions for clustering. The 3des keys enough to replicate between nodes - so it is suitable for stateless backend strategy.

The cons are

  • Harder to implement on server side, because for this solution have to implement the token generation / validation algorithm on server side For that server filter is recommended,.

  • The clients have to implement the store of tokens - instead of cookie browser session store is recommended - easier to stole cookies.

  • Have to make sure that the 3des keys are secured enough - Java security is recommended to use to avoid the comprimise.
1
public class SecureTokenGenerator {
public static final String CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

// 2048 bit keys should be secure until 2030 - https://web.archive.org/web/20170417095741/https://www.emc.com/emc-plus/rsa-labs/historical/twirl-and-rsa-key-size.htm
public static final int SECURE_TOKEN_LENGTH = 256;

private static final SecureRandom random = new SecureRandom();

private static final char[] symbols = CHARACTERS.toCharArray();

private static final char[] buf = new char[SECURE_TOKEN_LENGTH];

/**
 * Generate the next secure random token in the series.
 */
public static String nextToken() {
    for (int idx = 0; idx < buf.length; ++idx)
        buf[idx] = symbols[random.nextInt(symbols.length)];
    return new String(buf);
}

}

Taken and significantly condensed from https://stackoverflow.com/a/41156/584947

fIwJlxSzApHEZIl
  • 11,861
  • 6
  • 62
  • 71
1

Creating a unique token, it totally based on the logic and how many parameters you have used. Supplier functional interface of Java 8 helps you:

Supplier<String> tokenSupplier = () -> {

        StringBuilder token = new StringBuilder();
        long currentTimeInMilisecond = Instant.now().toEpochMilli();
        return token.append(currentTimeInMilisecond).append("-")
                .append(UUID.randomUUID().toString()).toString();
};

System.out.println(tokenSupplier.get());

Output:

1591457374665-d5eff25f-b083-41c3-a90d-a89adcc45043

You can learn more about it here- Java Token

Atul Rai
  • 332
  • 1
  • 10
  • 25
-3

REST is based on HTTP, and encourages using the underlying protocol rather than reinventing the wheel. HTTP uses cookies to support stateful interactions like remembering authentication, and also supports username and password authentication.

Furthermore, Java EE supports all this out of the box. Check the tutorial

http://docs.oracle.com/javaee/6/tutorial/doc/bncas.html

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
artbristol
  • 32,010
  • 5
  • 70
  • 103
  • 5
    -1 sorry but question is how can I create a token based authentication not if I can use cookies which I am aware that I can – Spring Dec 21 '12 at 16:16
  • 1
    -1 completely... "I want to use authentication tokens for login from mobile devices" mobile devices, not web clients. – Bogdan Zurac Mar 29 '14 at 08:59
  • 2
    @Andrew I don't understand your objection. Mobile devices are more than capable of using HTTP: that's the main way they commuincate. They can and should just save the cookie as the token. – artbristol Mar 30 '14 at 10:38
  • Why would you want to implement cookies on a mobile app when the session does not auto expire and it's much more simpler to just set an auth token inside the response body for both the client and the server. Furthermore, like Spring said, he was interested in creating an auth token in a general way, not how to actually send that token (via cookies or basic or whatever). I'm also interested in the best way to create an auth token, not how to actually send it on the request. Even in my case, like I said, it's much more simpler to send it in the body because I also save it db side. – Bogdan Zurac Mar 30 '14 at 16:11
  • @Andrew Go ahead and implement your own security protocol then. I'm sure that will work out just fine, because you're such an expert and all. Thanks for the downvote. – artbristol Mar 30 '14 at 20:45
  • 3
    @artbristol There are some security reason which is important to keep in mind. To store the token in cookie is not the most secure way on the client side because of session hijacking can be happen - some injected javascript can get your session token. More secure way is (but also not perfect) use token as HTTP head paramter and store on browser's session store. So in security context own security protocol is more secure as the standard java cookie based. I recommend for token to store some CRC checksum and expiration. For more information check: https://en.wikipedia.org/wiki/JSON_Web_Token – Csákány Róbert Feb 05 '17 at 10:01
  • @CsákányRóbert thanks for the suggestion, although the context is one of a mobile app, not a browser, so it's not relevant to this particular question. Furthermore cookies can be set to HtpOnly to prevent that kind of attack. – artbristol Feb 19 '17 at 13:37