I'm implementing a REST service that requires authentication. I cannot store any per-user state (such as a randomly-generated token) because my service does not have direct access to a database, only to another backend service.
The solution I came up with is creating a JSON Web Token (JWT) when the user authenticates. The JWT claims set contains the user ID in the Subject ("sub") field. The server then encrypts the claims set directly ("alg":"dir") using AES GCM with 256 bit key ("enc":"A256GCM") creating a JWE. The key is generated once when the service starts and stored in memory.
To authenticate, the client submits the username/password, and the server responds with the token described above. The client then sends that token with each subsequent request.
When the client submits the token with subsequent requests, the server decrypts it using the key, and assumes the user ID in the "sub" field to be the ID of the current user, without any further authentication checks. Token expiration is handled by the "exp" field in the JWT claims set.
The connection between the client and the server will use SSL/TLS, so the token will not leak.
I'm using this library to create and read JWTs as I don't trust myself to write correct cryptography code.
- Is the above approach secure? Can an attacker impersonate another user by manipulating the token?
- Is the approach over-complicated? Would using MAC (in other words: JWS) instead of encryption have the same security? (or possibly more, since it's simpler and there's less chance of making a mistake). There's nothing particularly secret in the JWT claims set, and the user knowing their own ID doesn't matter.
- Is my choice of JWE algorithm and encryption appropriate?
- For the JWE "alg", the library I'm using supports direct encryption (using the key directly to encrypt the claims set) and RSA (generating a new key to encrypt the claims set for each token, and encrypting the generated key with an RSA public key). I chose the former because it's easier to generate a symmetric key than an RSA key.
- For the JWE "enc", the library supports AES GCM and AES CBC HMAC SHA2 (with various bit lengths). I chose GCM arbitrarily.