My application consists of a nodejs back end API but I am also developing a "reference" implementation of a JavaScript client, which is a backbone SPA.
First of all; the API accepts only HTTPS requests, in case an HTTP request reaches the server it completely ignores it and also (depending on tenant configuration) invalidates the password provided on that insecure request.
My server is stateless and I am using only HTTP(S) basic authentication. I provide two ways of authenticating a request:
1- Sending credentials on header Authentication: base64('Basic ' + user:password)
2- Sending an authenticated request using method 1 to GET /users/current
which returns a token that is an encrypted string* containing: username + '|' + timeOfTokenExpiration
. Client then sends only header Authentication: base64('Token ' + username:returnedToken)
thereafter.
*Encryption is done with OpenSSL's aes-256-ctr algorithm, and key is user's password hash
Method 1 can be used for a straight server-to-server communication, but it is not suitable for a JavaScript client since the user would have to insert his credentials on every request, what is infeasible.
Storing user credentials on browser's local storage would solve this issue but would keep the user indefinitely logged, creating another possible security threat. Also I am not sure how secure it is to store credentials in clear text on browser's memory.
By using method 2 the JavaScript client would send only one authenticated request and then store encrypted credentials on local storage, after a given amount of time it has to revalidate user credentials since it will eventually expire and server will no long accept requests from that token.
At server side I check authenticity of a method 2 request by retrieving user's password hash and trying to decrypt it. After decryption I check if decryptedString.split('|')[0] === username
.
Is this a safe/good approach?
I check authenticity of a method 2 request by; retrieving user's password
: are you storing passwords unhashed ?