Managing SaaS Identity Through Custom Attributes and Amazon Cognito
By Judah Bernstein, Partner Solutions Architect at AWS focused on SaaS
Identity is a fundamental design decision that software as a service (SaaS) architects must consider when developing a multi-tenant system. Developers who are building SaaS applications must be able to identify a user, the tenant associated with the user, the user’s permissions, and the relationship a tenant has with the provider, such as usage plan or tier.
In this post, I will explore how to architect a multi-tenant system and identify tenant context and role using Amazon Cognito, which lets you easily add user sign-up and sign-in to your mobile and web apps.
I’ll first describe how to introduce tenant context into a multi-tenant application, and then define custom attributes and claims. Finally, I’ll present a few design considerations and show you how to take advantage of custom attributes within a multi-tenant system.
Introducing Tenant Context into Amazon Cognito
To secure and isolate multiple tenants within a SaaS application, you must inject tenant context into applications or infrastructure. Tenant context may consist of a customer (tenant) identifier, usage plan, user identifier, and application role. This allows an application to programmatically adjust to the agreement with the customer, scope the access of resources to the corresponding customer, and constrain the customer to the permissions defined by the application role.
You can inject SaaS applications with tenant context in myriad ways. One approach is to inject it into the token obtained following a sign-in to an identity provider. Amazon Cognito user pools provide you with an identity provider so you can introduce tenant context. This allows you to architect the application to be stateless, scalable, and secure.
Amazon Cognito also lets you add user sign-up and sign-in to mobile and web applications with a dedicated login using custom credentials, such as an email address and password. User pools provide a cost-effective, secure, highly available, and durable user directory that stores a collection of user profiles with standard and custom attributes. You can define these attributes by using key-value pairs, and then use these attributes within the application or infrastructure to regulate access control and maintain tenant context.
Standard Attributes and Claims
Amazon Cognito has a set of built-in standard attributes that match the attributes provided by the OpenID Connect (OIDC) specifications, such as given_name, family_name, email, and birthdate. These attributes are key-value pairs associated with a user profile.
Standard attributes limit the independent software vendor’s (ISV’s) ability to meet the requirements of a multi-tenant system. For example, defining a tenant simply by their email domain may result in challenges if you’re supporting multiple business units within an enterprise organization, or may prohibit a subsidiary of an enterprise from obtaining access to tenant data.
To bind tenant context, you should introduce custom attributes within the context of the authentication and authorization mechanism. Defining custom attributes within a user profile allows you to inject key-value pairs into an application, and supports the extensibility and identification of tenant context.
JSON Web Token and Authorization Claims
You can obtain tenant context by decoding key-value pairs that were injected into a secure authorization token, generated and signed by Amazon Cognito. This JSON Web Token (JWT) is issued and signed by a centralized server after a user is authenticated with their user name and password, as shown in Figure 2.
The issued token’s key-value pairs are claims obtained from profile attributes, which include details of the issuing provider. This may include details on the identity such as the user’s given_name, and custom claims such as the defined key-value pairs.
Design Considerations for Using Custom Attributes (Claims)
In a multi-tenant application, a client application generally will pass the obtained ID token to a multi-tenant service. The service is responsible for decoding and parsing the token, and assessing the corresponding claims to verify the user and tenant context, as shown in Figure 4. By tying together multiple claims, you can address varied and often complex requirements for how the user is allowed to access an application or infrastructure.
SaaS Examples for Custom Attributes
Developers can take various approaches to introducing custom attributes, identifying tenant context, and authorizing users within a SaaS application when using Amazon Cognito. You must understand the business requirements to determine the appropriate choice for your architecture.
I’ve put together the following references to describe some of these approaches.
Example 1 – Introduction of Custom Attributes for Tenant Context
One common approach to enforce tenant isolation is to define multiple custom attributes, which, when combined, uniquely identify the entity, its permissions, and its associated tenant. A unique tenant identifier, a role to designate permissions (for a user), and a universally unique alphanumeric string of the identity give the application sufficient context to assess the identity in a multi-tenant environment. This approach may be extended with additional business logic, such as a usage plan that provides hierarchical layers of features or usage.
A JWT token obtained following an authentication, as shown in Figure 5, might include four custom claims: tenant identifier (tenant_id), role (role), usage plan (tier) to determine the plan the tenant is subscribed to (free, standard, professional), and a universally unique identifier (sub) generated by the authorization server to uniquely identity the entity. In this example, you can integrate the required application code to assess the value within custom attributes, associate or generate the permissions required for the user, and provide the appropriate access.
Another example of this approach is when a user signs in to an application with their user name and password. The user is aware only of the functionality and data they have access to. They’re unaware that their tenant identifier is 4c7a2b201a57672bb748f821723d52c4, their role is TenantAdmin, their tier is Professional, and their sub is 5b6a5bad-f59b-48ad-8f2d-9785d5a455b2.
Custom attributes provide a transparent approach to providing identity and isolation, which is handled by the application’s identity platform. If the user submits a request to create a product, the service is responsible for verifying the signature of the JWT token, decoding the token to obtain the corresponding claims, and invoking the expected micro-service methods or functions with the corresponding claims.
Amazon Cognito user pools, when combined with Amazon Cognito Federated Identities, can match a role with a custom attribute, thereby associating a user who has a specific attribute with the AWS Identity and Access Management (IAM) policy. You can combine multiple custom attributes into a hash or map, and then assign this value as the criteria for the claim match. This allows for various permutations that can be used to assess the permissions required for the identity.
Example 2 – Introduction of User Pool Group
Amazon Cognito user pools give an administrator the capability to add groups and associate users with groups via the console, the AWS Command Line Interface (CLI), or programmatically. Doing so introduces specific custom attributes (cognito:groups and cognito:roles, as described in Figure 6) that are managed and maintained by Amazon Cognito and available within the ID token.
This approach simplifies the administration required for managing the required, mutable, and editable flags provided by the user pool’s custom attributes, by handing off the administration of these attributes to Amazon Cognito. In addition, user pools can associate a role with a group when combined with Amazon Cognito Federated Identities.
Example 3 – Combination of User Pool Groups with Custom Attributes
In some scenarios, custom attributes might be necessary within an application context, but the manageability of role association to claim match doesn’t meet a developer’s requirements. In this scenario, it might make sense for you to use custom attributes for application context, but leverage the group association for the tenant context, roles, and policies.
In Figure 7, John Doe is assigned to a group designated GroupName, has an association for the ReadOnly role, and has the custom attribute of customer:tier : Professional Tier. The role may be associated with the group through the Amazon Cognito association to simplify access management, but the custom attribute for the tenant usage plan may be maintained separately and without the need for additional permissions or a specific group.
By associating tenant-specific users that have shared custom attributes with a user pool group, you can use a hybrid approach to tenant isolation. You can then add custom logic into the application that is responsible for scoping the tenant-level access through the evaluation of the provided custom attributes. This approach to tenant-level security may be further solidified by associating users with tenant-specific groups or corresponding roles. This allows for a re-enforcement of tenant-level isolation for AWS resources by providing fine grained IAM access policies.
Example 4 – Introduction of User Pool Per Tenant
Multiple user pools provide a greater level of isolation between customers. This approach can be combined with the previous examples for additional flexibility. Providing one user pool per tenant is an acceptable approach to multi-tenancy and allows for customization of custom attributes per customer.
In this scenario, if you have customers with unique requirements, each requirement can be met with minimal risk to the remaining tenants of the system. Note that the application must be developed with the appropriate programmatic and strategic approach to fit these requirements.
There are some scalability considerations to evaluate in this design pattern, including AWS service limits, manageability of multiple user directories, and maintenance of application security. For more information about this model, see the Tenant Isolation Architectures whitepaper from AWS.
Example 5 – Maintaining a Multi-Tenant Identity Platform for SaaS Providers
This example targets ISVs who are interested in becoming multi-tenant (OpenID) identity providers, and allows you to consume the identity platform through customer-maintained Amazon Cognito user directories. As shown in Figure 8, an ISV can architect a solution in which tenants are SaaS providers that have tenants themselves.
Considerations: Introducing Custom Attributes
While the integration of custom attributes has significant benefits, there are some aspects developers should consider when architecting a multi-tenant system.
You should carefully consider the impact of introducing mutable or required attributes into an environment. For example, if a third party is able to manipulate the tenant_id attribute, this change could disrupt the consistency and security of the system. Therefore, you should decide which custom attributes are required and configure these as non-mutable.
Integrating permissions within the context of a user pool is important as well. If you introduce a custom attribute labeled role to maintain the permissions of a user within a tenant, you must define the attribute as mutable. This will be required to constrain the mutability of the attribute to approved users. SaaS architects commonly define a tenant administrator as the appropriate role and responsible party for maintaining tenant specific users and data.
We recommend that you complete a competitive review of potential identity solutions before your development cycle. During this review, it’s important to ensure that solutions allow for the introduction and mutability of custom attributes and claims. This allows for long-term extensibility of the SaaS identity architecture.
Next Steps: Identity with a Multi-Tenant Mindset
To streamline the move to a secure and agile multi-tenant system, we recommend that developers minimize the complexity required to identify and manage tenant context. Amazon Cognito enables you to simplify, secure, and scale your architecture with custom attributes. Offloading the management of tenant context and user roles to custom attributes allows a business to focus on its product and go-to-market strategy.
If you’re interested in understanding the design considerations for integrating custom attributes within a SaaS application, you can evaluate a SaaS reference architecture in real-time by deploying the SaaS Identity and Isolation with Amazon Cognito Quick Start within your AWS account.
The Quick Start equips you with a full working solution that digs into the nuances of injecting tenant identity into SaaS applications. It addresses a broad range of identity topics and illustrates how tenant context is introduced via Amazon Cognito and used in combination with IAM to scope access to tenant resources.
About AWS SaaS Factory
AWS SaaS Factory helps organizations at any stage of the SaaS journey. Whether looking to build new products, migrate existing applications, or optimize SaaS solutions on AWS, we can help. Visit the AWS SaaS Factory Insights Hub to discover more technical and business content and best practices.
SaaS builders are encouraged to reach out to their account representative to inquire about engagement models and to work with the AWS SaaS Factory team.
Sign up to stay informed about the latest SaaS on AWS news, resources, and events.