I am coming today because I would like to make sure I have the right approach in terms of microservice architecture for a login/register/authentication approach.
I first thought I would have 2 services:
API
Users Service
I would have the authentication process shared between my API and my Users Service. I would, by example, login from my API by trying to find the combination username/password in the users service, then on success, generating a token and returning it to the user. API would then handle the authentication token (in Redis or others)
However, moving forward into microservices and loosely coupling approach, I saw that some people actually split the Authentication data from the user data (such as age, first name, phone number, etc...). So I now have the following approach:
API (send the data to the authentication service. On success, it request addUser/getuserbyid of users service and then return the data)
Authentication Service (hold users account information)
Users Service (hold users information)
What's then the best approach? Because on fail, I don't know how can I manage.
Let's take the case where We can authenticate but the users service crashed because of another process. The user has a created account but no user profile. For that case, it makes everything harder..
Thanks for any interesting point of view :)
Related
I'm designing two micro services one for Teacher and other for Student. Now my question is what is the best approach of storing users and doing Authentication Authorization :-
Centralized Auth server which will store user roles as well as all the info.
Centralized Auth server which will only store roles but the user info will be Stored in the databases of their respective services (Student, Teacher)
No centralized Auth server but redirecting login request to either Student or Teacher as per the role in the request body and it will be the responsibility of Gateway.
I want to know the pros and cons of these approaches. If there is any better approach then please share the same.
P.S :- Multiple roles can be assigned to a single user.
I would go for the first approach. Rather than "centralized Auth" server it would be more of a "auth micro service".
Now the important part is how to handle authentication itself. In general you could either use a session or JWT.
For micro services I think JWT is a perfect fit. If you use session you basically "centralize" your authentication and authorization. What I mean by this is that after a user is authenticated, every time the user makes a request all the micro services that react to this response must check on the centralized session. This will not only increase latency but it just doest fit with the distributed system. The point of using micro services is to have make replicas of services and so scale horizontally.
If you use JWT, the micro services only need the secret key to validate the token. Basically no centralized store(session) for authentication infos.
About the "auth service", I would suggest you to store authentication and authorization related data only(including user info related to authentication. phone number, email, name etc. you probably would use this in case user needs to change password, forgot password etc.). Other specific data related to a specific role can be stored in the corresponding service.
I've done a fair amount of research on the many different ways to authenticate and authorize users who use my frontend application to access my REST API. I've built a system that uses OAuth2 and JWT and need a sanity check since I'm working on this alone.
For a bit of background, my frontend is built using Vue.js and my API is built using Django with Django Rest Framework. My team is already planning on concurrently developing the mobile and desktop versions of this app which both would require authentication and authorization as well.
To keep things brief, I'll omit the alternative solutions I have and just talk about the most controversial one.
Right now, OAuth2 (my authorization server) grants users a JWT token using ROPC when they provide their email and password to my frontend client. I should note that my API (my resource server) and authorization server live on the same machine.
My application allows users to essentially signup using different plans (for example a free plan and a paid plan). When a user signs up for a free plan, I need the frontend application to not only disable certain features and elements in the UI, but also I need the authorization server and or resource server to limit what that user is allowed to query based on their plan.
The idea is when a user signs up or logs in, my authorization server will get the associated user record from the database and create a valid JWT with a claim attached that states the user's plan and maybe some other non-personal information. Then once signed it sends it off to the user where the frontend can enable/disable parts of the UI... etc. Hence, if a user logs in on mobile, we can customize the UI based on the same claim sent by the JWT.
My issue is that I don't know if this is a good way to go about it. It seems that everyone I've asked in my circle is split on using JWT or not. Those apposed mostly raise security issues, but, when from what I understand, many of the JWT security pitfalls are well documented and can be avoided just using some commonsense as with any other session/token-based authentication. I'm starting to get analysis paralysis. Please help.
CLASSIFICATION
I would say this is really an API Authorization question, as opposed to an OAuth question:
The role of the Authorization Server and tokens is really just to prove the user's identity
Product specific logic comes after the user logs in and is generally best handled in your app
MY PREFERENCES
Here is how I would handle it:
Save the plan type to your product data when the user signs up
After login, look up the user from the access token
Then look up the user's plan type from your product data
Produce a Claims / Principal object in your API containing both
Enforce business rules based on the plan type claim
I would aim for a Claims object something like this:
class ApiClaims {
// The user id in the access token
userId: string;
// The email
email: string;
// The plan type
planType: string;
// Other claims from the token
// Other claims from product data, eg user roles
}
RESOURCES
If interested in this approach, these blog posts of mine may be of interest:
User Data Management
API Authorization
JWT?
You need some kind of API credential that is sent in HTTPS messages and is web and mobile friendly, so I would use JWTs. You could follow the same pattern with any API credential though.
It depends on what you are trying to protect of course, but JWT bearer tokens are an industry standard. Since you control both the client and the authorization server, you can implement it however you like.
I would look into changing Resource Owner Password Credentials flow to authorization code flow. It will enable you to use social authentication providers like Google or Facebook to sign in users (while still maintaining plan info in your own service). Chances are that people trust those companies more to keep their credentials safe than your company, and it allows you to benefit from any authentication features (MFA) those companies implement.
Also, if you want the clients to read the contents of the token, you should use OpenID Connect id_tokens, as those are guarenteed to be in JWT format.
I try to implement Oauth2/OpenId Connect into microservices architecture based on Java/Spring Cloud. My current problem is about tokens propagation between microservices or through a message broker like RabbitMQ.
Very few topics talk about this. I only found this Stackoverflow thread but I don't like proposed answers.
Here are the different cases :
My microservice A receives a request initiated by the end user going through the API gateway and carrying a valid access token (JWT with scopes/claims corresponding to the final user : username, id, email, permissions, etc.). There's no problem with this case. The microservice has all informations to process the request.
1st problem : What happens if microservice A needs to call microservice B ?
1st solution : microservice A sends the access token to the microservice B
==> What happens if the token expires before arriving at microservice B ?
2nd solution : use "client credentials grant" proposed by OAuth (aka service account). It means microservice A request a new access token with its own credentials and use it to call microservice B.
==> With this solution, all data related to the user (username, id, permissions, etc.) are lost.
For example, the called method in microservice B needs the user id to work. The user id value can be set as query string.
If the method is called with the user access token, the microservice B can validate that the user id value in query string is equal to the user id value in the JWT token.
If the method is called with the service access token, the microservice B can't validate the query string value and needs to trust the microservice A.
For this cas, I heard about the "token-exchange" draft from OAuth 2. The idea is very interesting. It allows microservice A to convert the user access token into another access token with less permissions but forged for microservice A. Unfortunately, this mecanism is still in draft and not implemented in a lot of products.
2nd problem : What happens if microservice A pushs a message to RabbitMQ and microservice B receives this message ?
1st solution : Authentication and authorization are managed by RabbitMQ (vhost, account, etc.)
==> Once again, all user related data are lost. Moreover, we have 2 repositories to manage authentication and authorization
2nd solution : Like the first problem, use "client credentials grant"
What do you think about it ? Is there another better solution ?
Thanks in advance.
It's quite straightforward. There are always two use cases that we will refer to as end-user and app2app. Always gotta handle both.
Consider a simplified architecture:
Internet
User ----------------> Service A +-------> Service B
HTTP request |
+-------> Service C
Assume the user is authenticated by a token. JWT or anything else, doesn't matter.
The service A verifies the user token and performs the action. It has to call service B and C so it makes the appropriate requests and has to include the user token in these requests.
There can be a bit of transformations to do. Maybe A reads the user token from a cookie but B reads the token from the Authorization: Bearer xxx header (a common way in HTTP API to accept a JWT token). Maybe C is not HTTP-based but GRPC (or whatever developers use nowadays?), so the token has to be forwarded over that protocol, no idea what's the general practice there to pass extra information.
It's fairly straightforward and it works really well for all services dealing with end-users, as long as the protocol can multiplex messages/requests with their context. HTTP is an ideal example because each request is fully independent, a web server can process various stuff per path and argument and cookie and more.
It's also an extremely secure model because actions have to be initiated by the user. Wants to delete a user account? The request can be fully restricted to the user, there can't just be an employee/intern/hacker calling https://internal.corp/users/delete/user123456 or https://internal.corp/transactions/views/user123456. Actually, customer support for example may need to access these information so there has to be some limited access besides being the user.
Consider a real-word architecture:
Internet
User ----------------> Service A +-------> Service B --------> SQL Database
HTTP request |
+-------> Service C --------> Kafka Queue
|
|
Service X <--------------+
Service Y <--------------+
Service Z <--------------+
Passing JWT user tokens doesn't work with middleware that do not work on a end-user basis. Notably databases and queues.
A database does not handle access based on end-user (same issue with the queue). It usually requires either a dedicated username/password or a SSL certificate for access, neither of which have any meaning outside of that database instance. The access is full read/write or read-only per table with no possibility of fine permission (there is a concept of row-level permission but let's ignore it).
So service B and service C need to get functional accounts with write permission respectively to the SQL database and the Kafka Queue.
Services X,Y,Z need to read from the queue, they also each need a dedicated read-only access. They don't strictly need to have a JWT user token per message, they could trust that what's in the queue is intended, because whatever wrote to the queue in the first place must have had explicit permission to write to the queue.
It gets a bit tricky if service X needs to call yet another HTTP service that requires a user token. That's hard to do if the token wasn't forwarded. It would be possible to store the token in the queue along the message, but it's really ill advised. One does not want to save and persist tokens everywhere (the kafka queue writes messages and would basically become a highly-sensitive token database, erf). That's where the forwarding of user tokens shows its limits, at the boundaries of systems speaking different protocols with different access control models. One has to think carefully of how to architecture systems together to minimize this hassle. Use dedicated service accounts to interface specific systems that don't understand end-user tokens or don't have end-user tokens.
I have developed a REST/JSON API. The API exposes a lot of features. The API will be consumed by applications we design internally (mobile apps and web apps), by applications designed by our resellers and by applications designed by businesses. I am looking at securing the application by implementing authentication and authorization. I have 'googled' a lot but my research has left me with more questions than answers.
Our internal application will be used by end users registered on the application. In essence, our application is just a client taking request from the end user, taking it to the REST API and retrieving the data for the end user. Our internal application should be able to perform all the operations exposed by the REST API. What is the best way to handle user login on our internal application? HTTP Basic over SSL or OAuth?
Our reseller applications can create users like they own the users but ultimately the user details get stored in our database. The reseller application will just act as a client taking request from the user and fetching user data. Our resellers applications should only be restricted to some operations of the REST API. What security mechanism will I use to implement this kind of authorization and user login?
I hope my question is clear. Thanks for the help.
From what I understood in reading this there are two parts to your question:
What is the best authentication method for my API?
I recently developed an authentication system for an API that was modelled on OAuth but didn't have every single one of their specifications. The system was basically the same as what Amazon use for their API. [This article]1 is very helpful if you want a secure API authentication model without having to use OAuth.
The model uses these principles:
Authentication data will be passed with every request to the API server
Requests will include a Unix timestamp from when it was generated
The entire request (including the timestamp) will have an HMAC hash generated and sent alongside the rest of the data. The hash is generated using a private key that only the API server and the API client know.
The API takes the data (including the timestamp), generates an HMAC hash using the private key for that user (identified by a user ID, user name, public API key, whatever) and compares it to the hash sent with the request. If this was successful, regular authentication proceeds and the request is processed. Note: the API will check the timestamp and compare it to its own to make sure the request has occured within a valid timeframe of, for example, 30 seconds, 5 minutes, 10 minutes, etc.
Of course, you can use regular HTTP authentication over SSL/HTTPS also, but I find this way to be very good because you achieve a high level of security without needing to implement every aspect of the OAuth protocol.
How you authenticate is up to you essentially. I prefer to go with methods employed by large, trustworthy organisations (such as Amazon). I personally didn't want to go the whole hog with OAuth like Twitter, Facebook etc.
How should I allow different users to access different endpoints in my API?
You should have an internal map in your API server which contains records allowing or denying specific API accounts from accessing certain endpoints. In my API server I decided that all endpoints would be "allow" by default, and I would specify which accounts would not be able to access certain endpoints.
You could also set up different groups or types of API access accounts which could have group permissions like this.
My suggestion would be to [read this article]2 twice, or three times, then read it again. Then, implement the methods suggested within.
Personally, I think the best method for ensuring as much security as possible is to restrict absolutely everything in regards to the request to be within a set of boundaries that you define, e.g. I want this endpoint to only be accessible by GET HTTP requests (all other HTTP methods will throw an error), up to 3 times daily per account, within a 30 second timeframe of request to server, only allow a narrow range of data to be returned, etc.
Limiting the HTTP method is very important to reduce the risk of your API doing things it shouldn't, especially with a RESTful API as endpoints can be used to do multiple things depending on the request method. You can even set your permissions for each API account to restrict certain methods on each endpoint, e.g. API user xxx can GET information from an endpoint but cannot POST, PUT, PATCH etc, or API user xxx2 can POST data but cannot GET any, etc.
[EDIT] 1 and 2: www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/ (not completely removing the link but keeping the url unlinked as it no longer works/redirects to random sites)
I'm building some RESTful API for my project based on Play Framework 2.X.
My focus is on the authentication mechanism that I implemented.
Currently, I make use of SecureSocial.
The workflow is:
An anonymous user calls a secured API
Server grabs any cookie Id (kind of authentication token) and checks for matching in the Play 2 cache. (cache contains an association between cookie Id (randomly generated) and the user Id, accessible from database.
If any matched, user is authorized to process its expected service.
If none matched, user is redirected to a login page, and when filled with valid credentials (email/password), server stores its corresponding authentication data on Play 2 cache, and sends the newly created Cookie containing only a custom Id (authentication token) to user and of course, secured through SSL.
While the cookie/token doesn't expire, the user can call secured api (of course, if authorized)
The whole works great.
However, after some search, I came across this post, and ...I wonder if I'm in the right way.
Indeed, dealing with cookies ("sessions" in Play's term), would break the rule Restfulness.
Because an api really considered as stateless should be called with ALL the needed data at once (credentials/tokens etc..). The solution I implemented needs both calls: one to authenticate, the other to call the secured API.
I want to make things well, and I wonder some things:
What about the use of Api keys? Should I implement a solution using them instead of this SecureSocial workflow? Api Keys would be sent at EVERY API CALL, in order to keep restfulness.
I think about it since I want my APIs to be reached by some webapps, mobiles and other kind of clients. None of all are forced to manage cookies.
What about OAuth? Should I really need it? Would it replace totally the usage of simple api keys? Always with this objective of several clients, this known protocol would be a great way to manage authentication and authorization.
In one word, should I implement another mechanism in order to be Restful compliant?
this is quite an old Q, but still worth answering as it may interest others.
REST does mandate statelessness, but authorization is a common exception when implementing.
The solution you described requires a single authorization process, followed by numerous service calls based on authorized cookie. This is analog to api keys or OAuth. There's nothing wrong with cookies as long as the service isn't of high-security nature and that you expire then after a reasonable time.
Integrating OAuth into your service sounds a bit of an overkill and is recommended only if you expose the API to 3rd parties (outside your organization).