The SaaS.Admin.Service module (aka Admin Service) is an API that has two main responsibilities:
- Preforming Create, Read, Update, and Delete (CRUD) operations on tenants
- Serving as a broker to the permissions API to assign roles and permissions to tenants
How to Run Locally
Instructions to get this module running on your local dev machine are located in the module’s readme.md.
Configuration and Secrets
A list of app settings and secrets can be found in the module’s readme.md. All non-secret values will have a default value in the
appsettings.json file. All secret values will need to be set using the .NET Secret Manager when running the project locally, as it is not recommended to have these secret values in your
When deployed to Azure, the application is configured to load in its secrets from Azure Key Vault instead. If you deploy the project using our ARM/Bicep templates from the Quick Start guide, the modules will be deployed to an app service which accesses the Azure Key Vault using a System Assigned Managed Identity. The Admin Service module is also configured with key name prefixes to only import secrets with the prefix of
admin-, as other modules share the same Azure Key Vault.
- Depends on the SaaS.Permissions.Service for CRUD operations on permissions records
- Identity Provider
- Depends on the identity provider to authenticate callers via their JWT token
Currently, the only consumers of this API are the 2 frontend applications. Every module in the ASDK project was designed to be extensible, so you could also build your own applications that interface directly with this API to fit other use cases that the included frontend applications do not provide.
The Admin Service is secured using OAuth 2.0 authentication via the Microsoft Identity Platform. Incoming requests must contain a valid JWT Bearer token in the
Authorization header. The token must contain a valid scope that the calling application has been authorized to use. To learn more about how this process works and is configured in Azure AD B2C, we highly recommend checking out our list of identity resources & documentation.
For authorization, we have also included middleware on the Admin Service that extracts the user’s permission records from the JWT token claims and performs authorization based on policies applied at the route level. In other words, before preforming any action on a tenant once a request is received, the admin service will first ensure that the user making the request has a claim to that tenant on their token. If there is no claim to that tenant, or their role does not match what they’re trying to do, the request will be denied.
Implementing this in a multitenant fashion is often the most difficult part of starting a SaaS project, so we tried to make it as extensible as possible to support a wide range of scenarios.
Entity Framework Core is used to manage the SQL Server Database schema and connections. We are using Code First Development and, if no data or schema exists in the database on application startup, the application will automatically create the database schema that is defined in our model files. If you make any changes to these models, you will need to preform a migration to upgrade the database schema.
Swagger and NSwag
The Admin Service uses Swashbuckle to generate the OpenAPI definition and a UI for testing. This definition is also consumed by the Signup Administration site to generate its client implementation for interfacing with this API. Read more about using it here.
In addition, it also uses NSwag to consume the OpenAPI definition for the Permissions Service to generate a client implementation for that. Read more about NSwag here.
FAQ and Design Considerations
Q: Why did we choose to use strings to store our IDs and not GUIDs?
- A: The default implementation that we chose is to use GUIDs for IDs, but store them as strings. This decisision was made so that consumers of the ASDK project would not be forced into using GUIDs, should they want to use something else for IDs.
Q: Why did we choose to not give the admin service its own Azure Key Vault?
- A: For simplicity, we decided to use key name prefixes to store keys for each module across the entire application into one Azure Key Vault. This is an acceptable approach, but, if necessary, you may choose to separate the secrets for each module into a dedicated Azure Key Vault.