AuthN and AuthZ for Joveo’s multi-tenant SAAS apps

Abhishek Chatterjee
Joveo Engineering
Published in
6 min readDec 20, 2022
Heimdall protecting Asgard

Applying modern identity management 3rd party tools to SaaS applications with complex access management.

Background

Assumptions:
The article is written with the assumption that the reader is aware of terminologies(OAuth, identity-server, resource-server, SAML, JWT, refresh token, claims, etc.) around modern authentication and authorization and also understands how they work in theory.

Joveo’s Business:

Joveo is a programmatic job advertising platform. We have clients who are direct employers, staffing agencies, and job boards.

These customers, for their recruitment needs, submit jobs to Joveo’s platform, and Joveo takes the responsibility of distributing these jobs to various job publishing websites like Indeed and Monster.com or some niche job portals like Nurse.com and thousands of others.

Joveo’s Customers

Joveo has different categories of customers like Staffing-agency, Job-boards, Recruitment process outsourcing, and Direct employer.

We offer multiple SAAS applications to these customers for managing their campaigns and tracking the performances of their campaigns and jobs. Some of our customers have their own customers who rely on Joveo’s apps to manage their campaigns and track performances.

Types of customers:

These applications are used by our customers and there can be different types of users who can access different sections of these applications.

  • Client creators: These users onboard clients with all their intricate settings
  • Campaign Managers: They create campaigns and assign budgets and bids and other performance-managing attributes
  • Recruiters: They set goals at the job level and apply bids and budgets at the job level
  • Admin and Managers: They have super-user access who can have broader access and it’s also defined per Joveo’s account. For eg., the Admin of ZipRecruiter might have different permissions than the Admin of Adecco

Problem statement

Existing Auth system

  • Joveo’s authentication had simple email and password-based login for all users that did not follow any standard protocol. The passwords were maintained encrypted (BowlFish encryption algorithm with random salt) in MongoDB. One email could log in to only one application. So if a user had to be given access to multiple applications, a dummy email ID address had to be created.
  • Also in an application, a user could have access to only one account. So a user ended up having multiple login credentials to access multiple accounts
  • We had a very rudimentary RBAC(role-based access control) system. We had global roles defined and we mapped permissions to different pages and widgets of our applications. We ended up having a huge amount of Roles and permissions and it was getting very difficult to maintain

What were looking to achieve

  • Authentication with Industry Standard Security protocols:
    We were looking to provide OIDC (Google sign-on) for internal users, username-password, and SAML-based authentication capabilities to our external customers
  • Single sign-on for all apps:
    Users must have a single login credential and should be able to navigate across different Joveo apps.
  • Multi-account access:
    Users must be able to switch between accounts as well within the same app (account-level access can be imaged as row-level security in a database)
  • Complex RBAC
    User’s access to various features and resources must be controlled via RBAC
  • OAuth2.0 authorization flow

Solution

We always had the inclination to buy compared to build philosophy. And it was known to us back then that there are plenty of vendors out there who support all modern Auth workloads like Safe encryptions, Password criteria, MFA, Social-logins, SAML, and OAuth2.0 authorization flows. These vendors also possess security certifications like ISO, SOC2, GDPR, and PCI-DSS which otherwise are lengthy and expensive to acquire.

We did extensive research and POCs on Auth0 (Currently acquired by Octa), and AWS Cognito, and Octa settled on AWS Cognito. We will come up with a comparison blog between Auth0 and AWS Cognito.

Problems with using 3rd-party tools

The problem came with multi-account with different role access on a single application. None of the vendors had any out-of-the-box solutions. The standard solution was to give a single or a list of roles to a user that would be applicable to all the applications and all the accounts a user had access.
Let us consider an use case below:

Joveo has 3 apps -> App-1, App-2 and App-3.
Two accounts -> Account-1 and Account-2
Two users -> User-1 and User-2

App-1 allows roles such as Admin, Campaign-creator, Campaign-manager, and Viewer
App-2 allows roles such as Admin, Editor, Operation-manager, and Viewer
App-3 allows roles such as Admin, Creator, Viewer.

User1 and User2 both can access Account-1 and Account-2, App-1, App-2, and App-3, and can have varied roles across apps and accounts.

This level of RBAC was not supported anywhere

How we solved using Cognito and an internal service wrapping Cognito

We decided to rely on Cognito for password management, Social-sign-on, MFA, and SAML flow. We also created a dedicated backend to participate in the OAuth flow.

High-level components

The backend service was responsible for maintaining the complex access configuration of a user. And also is responsible for supplying the exact role and permissions to Cognito that creates JWT tokens with custom claims. Though Cognito could not support the complex access configuration of a user, it does provide a hook that can be used as a plugin to fetch this list of permissions via AWS lambda.

[ 
{
"applicationId": "App-1",
"accountId" : "Account-1",
"role": "CAMPAIGN_MANAGER"
},
{
"applicationId": "App-1",
"accountId" : "Account-2",
"role": "ADMIN"
},
{
"applicationId": "App-1",
"accountId" : "Account-1",
"role": "RECRUITER_LEAD"
}
]

When a user logs in and chooses to navigate to one of our apps, she should land in one of the accounts she has access. Also, the app should understand the permissions of this user and allow features accordingly. We came up with the below flow to manage our use case. The flow for OIDC and SAML authentication has few more actors but otherwise is quite similar.

Sequence diagram for auth flow
  1. The user tries to login from Joveo’s login page with a username-password (or any other mechanism like OIDC or SAML). A login API is invoked to our internal authentication backend service
  2. The backend act as a wrapper to AWS Cognito’s authenticate API and invokes Cognito’s authentication API. Backend+Cognito=Identity-Server
  3. Cognito validates the request parameters
  4. Upon success, Cognito responds with a refresh token to the BE service
  5. BE service responds to the App with the refresh token. App holding a refresh token means the user is authenticated in the App.
    Now the authorization angle begins
  6. Based on the user’s choice of app and account, the app requests an access token from the BE service
  7. The BE service pushes the app:email: account combination in Redis for future reference
  8. The BE requests Cognito for an access token. But Cognito has no idea about the user’s account access and associated permission. It relies on a hook -> The PreTokenGenerationLambda.
  9. Cognito invokes PreTokenGenerationLambda to fetch custom claims
  10. PreTokenGenerationLambda requests the BE service to provide user permissions
  11. The BE service looks up the Redis to identify the account that is being tried to be accessed by the user and determines the permissions from its database(omitted in the diagram) and responds to the PreTokenGenerationLambda
  12. PreTokenGenerationLambda responds to Cognito with custom claims
  13. Cognito creates JWT with custom claims
  14. Cognito responds to BE service with an access token
  15. The BE service responds to the App with the access token
  16. The App accesses resource servers with this access token

Conclusion

Most of the vendors provide ready-to-use products for simple SAAS software. Though these vendors didn’t have a tailor-made solution for our authentication requirements, they provided enough hooks to plug in the required customizations. And the offerings are very similar across most of the vendors.

Preeti Sahani and Ishan Tiwari were the engineers who brought this solution to life

--

--