Audience: VeriPath operations staff. This guide covers onboarding a new clinic onto the AES signing infrastructure.
Clinic users do not need to follow these steps — they access signing via their GP Booking App.
When a new clinic is onboarded to use AES prescription signing, the following must be provisioned:
This guide assumes the AES Portal and its supporting services (aes-pki, aes-tsa, aes-signer) are already deployed and running.
The AES Portal supports multi-realm JWT verification — each clinic operates in its own Keycloak realm. The AES Portal dynamically resolves the realm from the token's iss claim.
https://auth.veripath.co.uk/admin/maple-surgery, test-client)The GP Booking App uses mozilla-django-oidc to authenticate users against this realm:
gp-booking-apphttps://{clinic}.gp.veripath.co.uk/oidc/callbackhttps://{clinic}.gp.veripath.co.uk/OIDC_RP_CLIENT_SECRET in the clinic's Django settingsFor each clinician who will issue prescriptions:
doctor)clinician roleThe following attributes are used by the GP Booking App. Set them under Users → {user} → Attributes:
| Attribute | Value | Purpose |
|---|---|---|
prescriber_type |
GP, DENTIST, NURSE, or OTHER |
Determines qualification label on prescription |
professional_registration_number |
e.g. 1234567 |
GMC/GDC/NMC number displayed on prescription |
org_id |
Clinic's org slug (e.g. test-client) |
Matches the clinic's Tenant record in the booking app |
Each prescribing clinician needs a digital certificate in the AES signer. Without this, signing will fail with "Certificate not found for clinician: [name]".
The certificate's Common Name (CN) must match the clinician's full name exactly as returned by CustomUser.get_full_name() in the GP Booking App (e.g. Doctor Clinician).
Issue the certificate via the AES PKI API:
curl -X POST https://aes-pki:8001/certificates/issue \
-H "Content-Type: application/json" \
-d '{
"common_name": "Doctor Clinician",
"org": "VeriPath AES",
"country": "GB",
"cert_type": "clinician",
"validity_days": 365
}'
Or via the PKI admin endpoint if accessible from a browser.
What happens:
/data/certs/{safe_name}.key/data/certs/{safe_name}.crtCheck the signer's certificate list:
curl http://aes-signer:8000/certificates
Each entry should show key_exists: true.
The following environment variables must be set in the clinic's GP Booking App deployment:
| Variable | Value | Purpose |
|---|---|---|
OIDC_RP_CLIENT_ID |
gp-booking-app |
Keycloak client ID for the clinic's realm |
OIDC_RP_CLIENT_SECRET |
(from Step 1) | Keycloak client secret for the clinic's realm |
OIDC_OP_AUTHORIZATION_ENDPOINT |
https://auth.veripath.co.uk/realms/{clinic}/protocol/openid-connect/auth |
Per-realm auth endpoint |
OIDC_OP_TOKEN_ENDPOINT |
https://auth.veripath.co.uk/realms/{clinic}/protocol/openid-connect/token |
Per-realm token endpoint |
OIDC_OP_USER_ENDPOINT |
https://auth.veripath.co.uk/realms/{clinic}/protocol/openid-connect/userinfo |
Per-realm userinfo endpoint |
OIDC_OP_JWKS_ENDPOINT |
https://auth.veripath.co.uk/realms/{clinic}/protocol/openid-connect/certs |
Per-realm JWKS endpoint |
OIDC_RP_SCOPES |
openid email profile |
Standard OIDC scopes |
OIDC_STORE_ACCESS_TOKEN |
True |
Required for passing user JWT to AES signing |
The AES integration is configured via the Django admin (/admin/integrations/):
AEShttp://aes-portal:8000aes-signer-satest-client)After provisioning, verify the full signing flow:
/admin) shows the new prescription in the recent list