Microservice Authentication strategy - authentication

I'm having a hard time choosing a decent/secure authentication strategy for a microservice architecture. The only SO post I found on the topic is this one: Single Sign-On in Microservice Architecture
My idea here is to have in each service (eg. authentication, messaging, notification, profile etc.) a unique reference to each user (quite logically then his user_id) and the possibility to get the current user's id if logged in.
From my researches, I see there are two possible strategies:
1. Shared architecture
In this strategy, the authentication app is one service among other. But each service must be able to make the conversion session_id => user_id so it must be dead simple. That's why I thought of Redis, that would store the key:value session_id:user_id.
2. Firewall architecture
In this strategy, session storage doesn't really matter, as it is only handled by the authenticating app. Then the user_id can be forwarded to other services. I thought of Rails + Devise (+ Redis or mem-cached, or cookie storage, etc.) but there are tons of possibilities. The only thing that matter is that Service X will never need to authenticate the user.
How do those two solutions compare in terms of:
security
robustness
scalability
ease of use
Or maybe you would suggest another solution I haven't mentioned in here?
I like the solution #1 better but haven't found much default implementation that would secure me in the fact that I'm going in the right direction.

Based on what I understand, a good way to resolve it is by using the OAuth 2 protocol (you can find a little more information about it on http://oauth.net/2/)
When your user logs into your application they will get a token and with this token they will be able to send to other services to identify them in the request.
Example of Chained Microservice Design
Resources:
http://presos.dsyer.com/decks/microservice-security.html
https://github.com/intridea/oauth2
https://spring.io/guides/tutorials/spring-security-and-angular-js/

Short answer : Use Oauth2.0 kind token based authentication, which can be used in any type of applications like a webapp or mobile app. The sequence of steps involved for a web application would be then to
authenticate against ID provider
keep the access token in cookie
access the pages in webapp
call the services
Diagram below depicts the components which would be needed. Such an architecture separating the web and data apis will give a good scalability, resilience and stability

You can avoid storing session info in the backend by using JWT tokens.
Here's how it could look like using OAuth 2.0 & OpenID Connect. I'm also adding username & password login to the answer as I assume most people add it as a login option too.
Here are the suggested components of the solution:
Account-service: a microservice responsible for user creation & authentication. can have endpoints for Google, Facebook and/or regular username & password authentication endpoints - login, register.
On register - meaning via register endpoint or first google/fb login, we can store info about the user in the DB.
After the user successfully logs in using either of the options, on the server side we create a JWT token with relevant user data, like userID. To avoid tampering, we sign it using a token secret we define(that's a string).
This token should be returned as httpOnly cookie alongside the login response. It is recommended that it's https only too for security. This token would be the ID token, with regards to the OpenID connect specification.
Client side web application: receives the signed JWT as httpOnly cookie, which means this data is not accessible to javascript code, and is recommended from a security standpoint. When sending subsequent requests to the server or to other microservices, we attach the cookie to the request(in axios it would mean to use withCredentials: true).
Microservices that need to authenticate the user by the token:
These services verify the signature of the JWT token, and read it using the same secret provided to sign the token. then they can access the data stored on the token, like the userID, and fetch the DB for additional info about the user, or do whichever other logic. Note - this is not intended for use as authorization, but for authentication. for that, we have refresh token & access token, which are out of scope of the question.
I have recently created a detailed guide specifically about this subject, in case it helps someone: https://www.aspecto.io/blog/microservices-authentication-strategies-theory-to-practice/

One more architecture perspective is to use nuget-package (library) which actually do authentication/token validaton. Nuget-package will be consumed by each microservice.
One more benefit is that there is no code duplication.

you can use idenitty server 4 for authentication and authorisation purpose
you must use Firewall Architecture hence you have more control over secutiry , robustness ,scalability and ease of use

Related

Questions about Native applications and openId Authorization code flow

I have a few concerns with an OpenId Connect strategy that I would like to use and have been unable to find specifics on what the security concerns may be and any glaring issues with it I am overlooking.
Currently, I have an OpenId Connect implementation using Openiddict with Authorization Code flow. For the client, I have a React-Native app using react-native-app-auth.
I see from other questions on SO and from issues posted on the Openiddict repo that the recommended approach to third-party providers (e.g. Google) is: Client -> Auth server -> Google Auth -> Auth server -> Client/Auth server code and token exchange
However, it seems that a better approach from a UX standpoint (when using a SPA or native app) would be to implement something similar to GoogleSignIn on the client and either handle the identity on the server using an IdToken or authorization code from Google. This introduces an issue as the flow previously recommended could not be used as the entire initial challenge and redirect from Auth server to Google Auth has been skipped.
I have seen that this issue is mitigated by not using the authorization code grant and instead implementing a custom assertion grant. This seems to be an alright approach but would require exposing a custom grant and handling the flow differently on the client and server for local and third-party logins.
My proposed solution continues to use the authorization code flow and instead of adding a custom grant type the client could just pass a third-party identifier "Google" and the token or authorization code in the additional parameters of the OIDC authorize request. The authorize endpoint could then detect the provider and token, perform token validation, create a user or principal from it, and create an authorization code to send back to the client for the code/token exchange. This flow would look like the following:
1. Get the id token from the provider Client -> GoogleSignIn -> Client
2. Pass token to auth server and initiate code / token exchange Client -> Auth Server -> Auth server Verify Google IdToken (JWKS, issuer, audience, provider specific validation, etc...) or exchange auth code -> Auth server -> Client/Auth server code and token exchange
One downside to this approach would be the additional hops to verify the token on the server side. If the token was returned from GoogleSignIn, they themselves said that it could be trusted. https://developers.google.com/identity/protocols/oauth2/openid-connect#obtainuserinfo
I see that it is generally recommended to place the auth server between the client and the third-party but in this process the server is still between the client and auth server but only after the initial exchange from the client and third-party.
Questions,
In general am I missing something with this flow?
In this case would it be necessary to verify the token on the server side?
Is there some better way to approach this that I have completely overlooked?
Am I making this too complicated and UX should not be this much of a concern?
Instead of adding the provider and token to the additional parameters would it make more sense to pass it in the body of a post request? I don't see the issue with passing it via query string but that's also part of the reasoning for the authorization code grant from my understanding.
Apologies in advance for anything I have missed or omitted for brevity that should have been included.
Thanks.
ARCHITECTURE
I'm not sure I understand the UX problem - your existing architecture feels really good. If you want to login directly to Google, just send an acr_values=google query parameter in the authorization redirect, to bypass any authentication selection screens. The exact value will depend on how Openiddict represents the Google authentication option, and some providers use a non-standard parameter such as idp. Have a closer look at the OIDC request parameters.
A key OAuth goal is that the Authorization Server (AS) - Openiddict in your case - shields your apps from all of the provider differences and deals with their nuances and vendor specific behaviour. Your apps then also only receive one type of token, and only ever use simple code. As an example, the Curity AS supports all of these options, none of which requires any code in applications.
APPAUTH AND UX
If a user is already signed in then it can, as you say, look unnatural to spin up the system browser and them it is dismissed immediately.
A common option is to show the consent screen or an interstitial page to keep the user informed - and the user clicks one extra button. This can also be useful for getting password autofill to work. My code example and blog post shows how this might look, though of course you can improve on my basic UX.
OFFLINE ACCESS
I find this term misleading, since refresh tokens are most commonly used when the user is there. Are you just asking how to deal with tokens in a mobile client? Aim for behaviour like this:
Standard messages for API calls with access tokens in an authorization bearer header
Standard refresh token grant messages to refresh access tokens - eg as in this code
Note also that mobile apps can save tokens to encrypted secure mobile storage that is private to the app. This can improve usability, eg by avoiding logins every time the app is restarted. You should think through scenarios such as stolen devices and token lifetimes though.

Authentication in microservices (different options, pros and cons)

I want to understand pron and cons of different implementation of single sign-on authentication and authorization in microservice environment. I came up with 3 solutions (see the diagram below).
What pron and cons does each option have? (I'm using Ocelot as gateway and IdentityServer4 as identity provider). Microservice A and Microservice B have it's own UI (SPA applications), Microservice D is REST API.
I will try to explain my point of view:
Option 1:
I understand that first of all you have to be logged against an identity server using user credentials and then create the cookie. I wouldn't recommend this option, first because as I can see you don't validate the cookie and it contains the userId that it is propagated to the servers, so the user could change the userId to get information about other users. And second, because this approach makes you to have a cookie policy
Option 3:
As I can see, in this option you are doing the login on each application. So, if in the future you have other applications you will have to implement the login page and logic in each of them.
Option 2:
I think it is the best of them, but I would make a change. First of all, it is a good option to have an api gateway that take care of cross concerns like authentication/authorization talking to the identity server to request acces tokens and to try to call the services. Doing this you will have a unique login point and the gateway could check the permissions (scopes) to do the actions required by the user, so the services wouldn't have to take care of this. The only thing I would change is the validation in each of the services. Because the nature of JWT tokens, it will contains all info needed to validate itself (expiration time, issuer, audience.. etc) so this validation won't be necessary. And to avoid the possibility of manipulation, the best approach is to sign the token by trusted certificate and let the gateway check the integrity, so when the token reach the services you have the confidence that this is a valid user with proper rights to do the action

How to use OpenID or OAuth for internal first-party authentication?

I am working on an internal authentication system for users of a set of of RESTful web applications. Our intention is that a user should be able to sign-on once via a web form and have appropriate access to all these RESTful applications in our domain, which may be distributed in a private cloud across many servers. (I understand already that having a single authenticated session is not aligned with a pure RESTful approach, but this is a usability requirement.)
The applications themselves will be written in a variety of programming languages so a language-neutral approach is required. It was suggested to me that we might use OpenID or OAuth or a similar framework to handle the authentication but my understanding is that these are intended for third-party services and not the first-party services that would share data on our internal system. In this case, we might have a central provider service with all the other applications treated as third parties (or relying parties).
Questions:
Are OpenID/OAuth suitable for authentication among first-party services?
If so, how would one be advised to set up authentication for this use case?
Wouldn't a user have to grant individual permission to each first-party server that they wanted to use, just as they would need to grant individual permission to any third-party server? I think this would violate the requirement of having a single sign-on for accessing all the first-party services.
Are there good examples of sites supporting this first-party use case?
What would be a good alternative framework for this first-party use case?
You do not need OAuth for SSO services.
The primary use/advantage of OAuth is, as you know already, granting access to a 3rd party app to access/use your resource in a controlled manner.
Rather than having an authentication/authorization server that you would need for OAuth, why not use a single log in service across all your APIs. An OAuth access token is totally different from what you need.
As far as I understand, what you can have is something like OAuth in a way that your server vends out tokens to the app. (I'm assuming that it's a totally internal system, so tokens cannot be misused).
So basically what I'm proposing is:
When an app tries to access the first API it's redirected to a web-form.
The user enters credentials and is taken to the DB for verification. Let there be a service that generates a token for the user/app
Next API access request would be made with that token - the token uniquely identifies the app
Depending on the level of security you need you can sign some text using HMAC and send it as token, or if its totally internal just generate a unique identifier for the app/user and send it to other API
On receiving the token, each service first calls the main server with the token and internally fetches the corresponding customer/user ID and performs the required function.
In short separate the login + token generation + token verification into a different module. All APIs should use this module for login/token verification.
What I have proposed here works like OAuth but all security aspects have been stripped down since you want to use it in a private cloud.
Oauth supports multiple different kinds of flows. You can use the client crendentials flow from Oauth 2.0 to avoid asking the user to grant permission for every app (this is intended for the cases where you control both the server and the app or where you want to preauthorize certain apps). This post does a good job explaining everything: http://tatiyants.com/using-oauth-to-protect-internal-rest-api/

Is using SAML bearer tokens for authenticating users to backend services a bad idea?

Suppose I have a front-end application that wants to fetch some data from a back-end service. (I do.) The service will need to verify that the end-user is authenticated, that it is authorized to use the service and possibly filter the returned data based on the user's privileges. In my case, both the front-end app and the back-end service relies on Azure ACS for authentication.
Ideally the front-end would like to act on the behalf of the authenticated user, which sounds like a good fit for using an ActAs token (as specified in WS-Trust). However, it turns out that ACS does not currently support ActAs.
A workaround could be to use the actual bearer token (the bootstrap token in the front-end app) to authenticate to the back-end service. It's not hard to do, but would it be a bad idea for some reason?
From your front-end app, you could certainly pass along the identity data of the end user by either sending the token as is or sending the attributes from it. Both have issues. For the former, if it's also encrypted, the front- and back-ends will have to share the private key needed to decrypt it; they will also have to share audience restrictions, etc. in order for the back-end to consider the token valid for it. In other words, the front- and back-ends will be ONE relying party, not two. Might not be a problem, but be aware. In the latter case, you end up sending user data in a proprietay way which could increase integration and maintenance costs over time. In both cases, you can authenticate the front-end app to the back-end using some other type of credential, e.g., a certificate used at the transport level and, thus, forming a trusted subsystem between them.
One thing that I would suggest you consider instead is OAuth 2. From this blog post, it seems to me that ACS supports it (though I don't have any first hand experience w/ it). The truely wonderful thing about OAuth 2 is that it bakes delegation in, and is NO WHERE near as complex as ActAs in WS-Trust. The net result is the same, i.e., the back-end service will have info about the calling service and the end user, but the amount of effort to get it setup in incomparable. The tokens will still be bearer tokens, but you can mitigate that to a degree by using SSL. Beyond SSL, you can put some additional measures in place, but the best, IMO, would be if Microsoft did something in ACS like Google has done w/ their Access Tokens for service accounts which uses asymmetric keys that are chained up to a PKI. (BTW, for all I know, Microsoft may have already done something like that; if so, you're set.)
Anyway, HTH!

How to use OpenID in RESTful API?

I'm building Pylons-based web application with RESTful API, which currently lacks any authentication. So I'm going to implement that and in order to avoid all the trouble and caution with storing user passwords, I'd like to use OpenID for authentication. What would be the best way to do this? Are these two things compatible? Are there existing REST APIs that use OpenID that I can take inspiration from?
I've now spent some time researching the options and would like to summarize the findings.
First, a little bit more context -- I develop and control both the service and API consumer. Consumer is Flash-based app that is served from the same host the API is now and is supposed to be used in browser. No third party clients in sight yet.
So the question can be divided in two parts,
how do I do the OpenID authentication via API
how do I maintain the "authenticated" state in subsequent requests
For first part, OpenID authentication almost always includes interactive steps. During the authentication process there will most likely be a step where user is in OpenID provider's web page, signing in and pressing some "I agree" button. So API cannot and shouldn't handle this transparently (no "tell me your OpenID provider and password and I'll do the rest"). Best it can do is pass forth and back HTTP links that client has to open and follow instructions.
Maintaining "authenticated" state
REST APIs should be stateless, each request should include all the information needed to handle it, right? It wouldn't make any sense to authenticate against OpenID provider for each request, so some kind of session is neccessary. Some of the options for communicating session key (or "access token" or username/password) are:
HTTPS + BASIC authentication ("Authorization: Basic ..." header in each request)
Signing requests Amazon-style ("Authorization: AWS ... " header in each request)
OAuth: acquire Access Token, include that and a bunch of other parameters in each request
Cookie that stores session key ("Cookie: ... " header in each request)
Signed cookie that stores session information in the cookie itself
There's just one API consumer right now, so I chose to go for simplest thing that could possibly work -- cookies. They are super-easy to use in Pylons, with help of Beaker. They also "just work" in the Flash app -- since it runs inside browser, browser will include relevant cookies in the requests that Flash app makes -- the app doesn't need to be changed at all with respect to that. Here's one StackOverflow question that also advocates using cookies: RESTful authentication for web applications
Beaker also has nice feature of cookie-only sessions where all session data is contained in the cookie itself. I guess this is about as stateless as it gets. There is no session store on server. Cookies are signed and optionally encrypted to avoid tampering with them in client side. The drawback is that cookie gets a bit bigger, since it now needs to store more than just session key. By removing some stuff I didn't really need in the session (leftovers from OpenID authentication) I got the cookie size down to about 200 bytes.
OAuth is a better fit for API usage. Here's an example of OAuth in use in Python: oauth-python-twitter. Leah Culver's python-oauth library is the canonical implementation of OAuth in Python, but python-oauth2 is a recent contender that is getting some buzz. As for inspiration, django-piston has support for using OAuth to do auth when creating RESTful APIs for Django, though the documentation isn't as nice as I'd like for that particular topic.
If you build API, you could check OAuth protocol. It's complementary to OpenID.