Dev Portal Architecture
1up DevPortal is a public app built in the 1up Console and configured in a single realm. It will be linked to from the 1up website. Third party developers can self-register for a user account through a custom registration flow. At first, they are immediately able to create ‘sandbox’ clients to access test data in our Patient Access and Provider Access endpoints. They can then fill out production access forms, be approved for production access (manual review process initially), and begin to create production clients.
Single realm concept
-
There is one single dev-portal realm in each MTE, wherein:
-
The 1up Dev Portal is deployed and configured
-
Users self-register
-
User accounts live (in Keycloak)
-
Clients that 1up Dev Portal users create live (In Keycloak)
-
Both ‘sandbox’ and ‘production’ users and clients exist.
By keeping the Dev Portal to a single realm, users only need to create and manage a single client (set of client credentials) for each given access type (i.e. patient access or provider access). To enable these credentials to authorize across 1up’s ecosystem, the Dev Portal implements a unique solution on the back end for each client access type, which enables the client’s credentials to authorize across 1up end to end flows. Each of these solutions are documents in the production client data flow section of this document.
Component Architecture
Components
1up-console
The Dev Portal is built in the 1up-console repository (Next.js).
Terraform
The Dev Portal is configured in the dev-portal realm in each MTE, and the deployment is managed via Terraform here, where each MTE has a corresponding .tfvars file with a ‘deployments’ section that maps the realm to the developer subdomain:
deployments = [
{
subdomain = "developer"
realm_key = "dev-portal"
}
]
This means the deployments live at url's like:
https://developer.console.<MTE_BASE_URL>/1up-dev-portal
Postgres
The 1up-console uses a postgres database and the tables that are relevant to setting up the Dev Portal can be read about here.
To connect to the database, follow these steps:
Follow these instructions to get StrongDM access, and gain access to the desired MTE by filling out the ‘Strong DM Access to PHI Resources’ Okta request here.
Connect to the 1up-core-<MTE>-oneup-console-root-admin resource in StrongDM.
Connect using:
host/socket from the StrongDM resource (will look like 127.0.0.1)
port from the StrongDM resource (will look like 10668)
user: pguser
database: console
The keycloak_user_client_mapping table is referenced in code, and is an important component of the Dev portal. This table stores pairs of Keycloak user id’s and client id’s and it is how we track which clients were created by which user.
Tech Debt:
Currently, with the implementation of this table, we must make a call to Keycloak get all clients, then make a call to the postgres table to get a list of client id’s associated with the user’s id, before finally filtering the Keycloak clients for only the ones ones that are associated with the user. This is how we only show the user the clients they have created.
There is a tech debt ticket to explore using client attributes instead, and the possibility of simply including the userId in a prisma query to get clients. This could make client fetching much more efficient but needs to be explored first.
Keycloak
The Dev Portal in configured in a dev-portal realm in each MTE, and has a lot of unique configuration. If you need to set up or duplicate that realm, you can find info on how to do that here.
Core-Infrastructure
Keycloak-extensions
The Dev Portal’s custom registration flow is built here using the Free Marker Template (.ftl) file system that Keycloak offers. To work on this flow:
Run core-infrastructure locally, and access the locally hosted instance of Keycloak at http://localhost:8500, signing in as username admin and password password.
At the time of this doc, there is currently a dev-portal-clone realm in the local Keycloak instance, but if that is gone you can use the export/upload from JSON process described here to get a new dev-portal-clone realm into the local Keycloak instance based on the dev-portal realm in core-dev.
Use a local registration link, where the client_id query parameter is the client id of the dev portal client in your dev-portal-clone realm. Note the redirect_uri here doesn’t matter, there is nothing local to use, just put something random:
http://localhost:8500/realms/master/protocol/openid-connect/auth?response_type=code&client_id=cd3a8c99-dacf-434e-bef6-3a91b168a6f0&redirect_uri=<anything, google.com even>
There is little if any documentation online about how to develop a custom Keycloak registration flow like this, but it is really just html, and essentially how it works is you are replacing the built-in registration flow components Keycloak offers with custom html. The flow is then configured in the realm under realm settings > themes.
If you find yourself working on this or developing something similar, read this doc. General resources are going to helpful too, such as public repos, AI tools like Chat GPT and Cursor, Youtube tutorials, trial and error, and of course fellow 1up engineers who have worked on these (@Jessi Velazquez built this one).
Infrastructure-api
Infrastructure-api is a 1up wrapper on Keycloak’s admin API built so that all calls to Keycloak’s admin API must go through our service routing gateway.
You can read about infrastructure-api here: Keycloak Admin Wrapper APIs
This is a great doc to help understand working the 1up service routing gateway:
1up Gateway Crash Course
The Dev Portal uses this API in all of its interactions with Keycloak to create, update, delete clients.
There is a Postman collection you can use to interact with these API’s.
In order to use the Postman collection, you will need to get a Bearer token for the MTE first using the proxy-client. Core dev example:
curl --location 'https://gateway.1upcoredev.com/auth/realms/1upcoredev/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=proxy-client' \
--data-urlencode 'client_secret=Rkm5VGlx3vYlnKtGrv9Q13AP7OGnpE6x' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'scope=email'
--data-urlencode 'gateway-auth|core-infra-admin'
AWS
Specific AWS services worth mentioning here are:
Simple Email Service + IAM
We use this to send emails from code. This includes the internal email notifications sent when.
A customer submits production access forms.
If a production patient access client fails to sync with all -member realms.
Cloud Ops PR to set up the Terraform configuration can be found here.
Parameter Store
We set the following two variables and use these in code as sender and recipient for the SES email sends mentioned above:
/1up-console/PRODUCTION_REQUEST_SENDER_EMAIL
/1up-console/PRODUCTION_REQUEST_RECIPIENT_EMAIL
nt.