Spring
Spring

Reputation: 11835

How to create an authentication token using Java

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

Answers (7)

Atul Rai
Atul Rai

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

Dmitriy Dumanskiy
Dmitriy Dumanskiy

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

fIwJlxSzApHEZIl
fIwJlxSzApHEZIl

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

Daniel de Zwaan
Daniel de Zwaan

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

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.

Upvotes: 1

artbristol
artbristol

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

ireddick
ireddick

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

Related Questions