Once again we enter the scene with the developer manager trying to figure out what the best way to secure the applications are. This one is different from the API gateway since it is meant for users and not just automated access. The additional wrinkle is that as part of this project we wanted to add SSO to our reporting portal, a soon to be built order entry portal, and a client invoicing portal. So three different apps, one being migrated from Web Forms, one a third party product, and another a new customer portal for order entry.
Off into the ether I went to figure out what was the best way to go. Since we wanted SSO with multiple applications, including at least one but probably more third party applications, it was quick to say we needed some sort of security server and a common protocol, SAML, OATH2, OpenID Connect etc. We also didn’t want our clients to be in our Employee ID and SAML providers that are not AD are few and far between. So that narrowed it down to some sort of JWT based authentication, either home rolled or a service of some sort. After looking over all the various options OpenID Connect was the obvious winner for protocol since there was wide support and a large array of cloud based OpenID Connect identity providers.
The first thought was IdentityServer4 but once I started looking at that I knew I didn’t want to handle the overhead of setting up the service and wanted a nice packaged soltion, either click install and add some config or a managed service. Since there weren’t many packages out there, a manged service was the next step.
So for managed services there are quite a few but we already have resources in AWS (EC2, RDS, etc) and Azure (Azure AD, Office 365 etc) so either one of those would be an easier sell than bringing in another service. The additional benefit is that for up to 50,000 monthly active users, both solutions are free. The app will be small enough to fit well within those limits so either one would work.
So after working through and making a list of all the options it came down to three, IdentityServer4, AWS Cognito, and Azure AD B2C.
IdentityServer4 is a great product if you want to run your own IDP with OpenID Connect and dont mind the back end configuration. It’s just the OpenID Connect piece though. You still need to figure out the identity store (many people use the Microsoft Identity Framework with EF Core for the storage provider) and a full UI for configuragion of the users, client applications, claims, scopes, and everything else.
The good folks who author IdentityServer4 do have an admin ui package that you can purchase or there are a couple third party open source alternatives so that would not have been too much of a hurdle. The main hurdle was supporting the Security Token Service and making sure its up to date and free of any security holes (we dont want something like ZeroLogon coming about and having to do a mad scramble to fix our infrastructure).
So with the additional overhead this was out unless nothing else would work for our needs. It’s additional overhead but we could customize the hell out of it.
AWS Cognito was pretty quick to get up and running (another post coming on that), follow a couple different tutorials since there didn’t seem to be a good tutorial on React front ends and ASP.NET Core Web API back ends but there were enough for each to piece things together and get a working solution.
The next step was hooking Cognito up to our AD via SAML to handle our internal employee users since they will have users in all the various applications as well. This also let us use our AD groups for AWS Security through mapping the Groups claim from the SAML feed to a custom attribute on the user. We are then able to use the Pre Token Generation trigger to run a lambda function to “Add” the user to any cognito groups as needed. Everything went pretty smoothly with that integration and mapping the AD attributes to Cognito attributes is a simple
SAML key -> Cognito key with a text box for the SAML claim and a drop down of the various attributes that are in cognito.
The one issue I ran into is that the AWS Console is very limited for user modifications. If you want to set the various attributes that aren’t required when a user signs up you need to use the AWS SDK. The documentation on the AWS SDK is very thorough and with AWS Cognito Federated Identities in addition to the user pools, authorization was handled with IAM policies to ensure only users with the proper permissions could update other users.
With Cognito set up and running it was time to get the next one plugged in to figure out which would be better.
Azure AD B2C
Azure AD B2C is microsofts entry into the customer identity market. Overall it was functional and once configured would have been functionally the same as cognito. Configuring it was harder compared to AWS Cognito.
First to use Azure B2C you need to create a new AD tenant which is a chore in itself. (Thankfully I only got the high level overview and our IT handled that part, however there are walkthroughs out there to handle this process).
After the B2C tenant was set up we configured the apps. This was took some work. In order to log in or sign up you need to configure a user flow to allow signup, the signin user flow wont auto create users from your third party IDP, you have to use the Sign In or Sign Up user flow. You also need to pass which user flow to use as part of your oath redirect so its just one more place that stringly typed integrations can go wrong.
I never got to the attribute mapping since that was going to require a custom policy for the user flow. and by the the time I found the information on how to do it I had decided that AWS Cognito would be the better option, not because of anything objectively better between the user pool services though, its all about things outside the Azure B2C vs Cognito User Pools evaluation.
Eventually Ill get a post up on configuring Azure AD B2C since I want to have it around in a way that would make the most sense to me.
Making the decision
As part of the migrated app we need to host user images in a cloud data store. Since we are staying with AWS that will be an S3 bucket for the storage. AWS Cognito won simply because of the Federated Identities and the ability to issue temporary IAM credentials with the user pool as the authentication and use the groups and attributes for rules on which IAM policies should apply. This was the thing that made the decision. Nothing around the actual Security Token Service, the differences in configuration, or the fact that only AWS could have a custom URL for our company. It was purely the ease at which we could secure access to our other cloud resources and how seamless the integrations were.
So which one should you choose? If you are not using something like ookta or Auth0 and have decided to use an identity provider solution in a cloud that you also have compute resources in, use the one from your cloud provider. You are most likely already pretty locked in with the various services already in use and the identity provider of the cloud vendor will tie in to the other services pretty seamlessly. So if you’re in the Azure cloud, use Azure AD B2C. If your in the AWS Cloud, use AWS Cognito. The integrations with other products make things really simple to make the call.
For the AWS example, you can use your User Pool generated tokens with an AWS API Gateway to secure access to the Lambda Function invocations and S3 buckets that are fronted by the gateway. That ease of configuration is the entire reason for the decision. Nothing in the various implementations since they are close enough to call the same from the 20k foot view.