Reputation: 11835
On my Java EE6, REST service, I want to use authentication tokens for login from mobile devices. The user will send their username and password, and the 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 APIs?
Upvotes: 42
Views: 136274
Reputation: 354
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
Upvotes: 2
Reputation: 12787
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.
Upvotes: 53
Reputation: 13290
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
Upvotes: 1
Reputation: 3105
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.
Upvotes: 18
Reputation: 639
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:
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.
Upvotes: 1
Reputation: 32407
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
Upvotes: -3
Reputation: 8418
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?
Upvotes: 9