I have:
- myApp (server 1)
- User-Authentication Microservice + Users Database (server 2)
User-Authentication Microservice has a REST API through which I can manage users (create/delete users, update user data, get the list of all users, check user password, etc.)
Now I need to implement authorization/authentication:
- between user and myApp (for this I'm going to use regular sessions (cookies containing only session ID) and store session data in Redis)
- between myApp and User-Authentication Microservice (for this I assume I need to use some sort of API Key/token)
myApp app doesn't have direct access to Users Database, all communication handled only through User-Authentication Microservice.
For the past week, I've been reading extensively about authorization/authentication in REST APIs but still can't figure out how to build a solid authorization/authentication system for both user -> myApp and myApp -> User-Authentication Microservice.
Here is what I've come up with at the moment.
Sign Up (Diagram):
- User signs up sending username/password/other data to myApp
- myApp sends username/password/other data to User-Authentication Microservice
- User-Authentication Microservice creates a new user in Users Database
Sign In (Diagram):
- Now, user signs in sending username/password to myApp
- myApp sends username/password to User-Authentication Microservice which verifies username/password
- If username and password are correct, User-Authentication Microservice generates API Key (random string) and saves it to Users Database, associating this API Key with the user record:
username | password | email | address | APIKEY ---------+----------+-------+---------+----------- steve | n8Y5e... | ... | ... | D4ED43...
- Then User-Authentication Microservice returns saved API key (+ some additional information about the user it belongs to) to myApp
- myApp creates a new session storing it in Redis: generates session ID and saves session ID + API key + other session data to Redis:
sessionID: 9w72tv3MHZD... session_data: { "cookie": { "originalMaxAge": ..., "expires": ..., "httpOnly":true, "path": ... }, "user": { "authenticated": true, "username":"steve", "apiKey": D4ED43C0..., "created": ... } } expire: ...
- Finally, myApp server sends a response with a cookie containing session ID.
- Done, user signed in.
Upon each subsequent request (Diagram):
- User sends a cookie containing session ID
- myApp server compares session ID with the one stored in Redis.
- If they match, myApp looks into session data again, retrieves the API key associated with the session ID and sends this API key to User-Authentication Microservice
- User-Authentication Microservice looks up the user in Users Database by the API key. If the provided API key exists, it means that the user associated with this API key is authenticated.
- User-Authentication Microservice grants access by returning something like
{ authenticated: true, username: "steve" }
to myApp - myApp uses this response to grant/restrict access to pages/app features
Sign out (Diagram) (first 4 steps are precisely the same as in "Upon each subsequent request" above):
- User sends a cookie containing session ID
- myApp server compares session ID with the one stored in Redis.
- If they match, myApp looks into session data again, retrieves the API key associated with the session ID and sends this API key to User-Authentication Microservice
- User-Authentication Microservice looks up the user in Users Database by the API key. If the provided API key exists, it means that the user associated with this API key is authenticated.
- User-Authentication Microservice deletes API keys from Users Database and responds with something like
{ authenticated: false }
to myApp - myApp sees that the user is not authenticated and deletes all session data from Redis.
- myApp also "deletes" the cookie by setting its expiration date in the past and the user is signed out.
The question: Am I doing it wrong? What should I change? I've never built authentication for APIs before so I would appreciate any recommendations. I want to understand the "big picture".