Documentation

Third-Party Application (TPA) Registration

Overview

The Third-Party Application (TPA) Registration flow lets external SMART-on-FHIR application developers self-register for access to DHCS Patient Access APIs, in compliance with CMS-0057-F (42 CFR §431.60(b)(6)). Registration is developer-driven. DHCS does not gatekeep a patient's choice of application. The portal collects the technical details required by the OAuth authorization server (managed by EIAM), records an attestation to applicable privacy obligations, and provisions client credentials automatically once the developer confirms their first per-API access request.

This section walks through when to use TPA registration, how to complete it, how to manage credentials over time, and how to self-revoke.

Prerequisites

  • Portal access
    Make sure you are registered and can successfully log in to the DHCS Developer Portal with your credentials.
  • Application details ready
    Have your application name, HTTPS redirect URI(s), privacy policy URL, and organization contact email on hand before starting the wizard.

Getting help: If you need assistance with TPA registration, please open a request through the Support tab.

When to Use TPA Registration vs a Standard Access Request

Use TPA registration if you are an external developer building a patient-facing SMART-on-FHIR application that connects to a DHCS Patient Access API (or any API marked as CMS-0057-F-compliant on its API detail page). TPA registration is the only path that avoids a discretionary DHCS approval gate, which CMS-0057-F requires.

Use the standard access request flow if you fall into any of the following categories:

  • Internal DHCS developer with EIAM-provisioned org and role
  • External vendor developer with a business relationship to DHCS (billing, claims, eligibility, provider directory, etc.) accessing a non-Patient-Access API
  • Team lead or org admin requesting access on behalf of an internal team

The Home page persona tiles help you decide:

  • Third-Party App Developer goes to TPA registration (this section)
  • External Vendor Developer, Internal DHCS Developer, API Producer go to the standard Accessing an API flow

If you are unsure which applies to you, submit a request through the Support Center link in the footer.


Confidential vs Public Clients: How to Choose

During registration you select a FHIR client type. DHCS supports two client authentication modes today:

  • Confidential: the application can safely store a secret (server-side apps, backend services). Authenticates to the OAuth token endpoint using a client_secret provisioned when your first per-API access request is confirmed. Most integrations should pick this.
  • Public: the application cannot safely store a secret (browser-only SPAs, native mobile apps without a backend). Uses PKCE (Proof Key for Code Exchange) at the token endpoint; no client_secret is issued.

Confidential-asymmetric (private_key_jwt with a JWKS URL) is not yet supported by the DHCS registration flow. See the notice on Step 2 of the wizard. If your application requires asymmetric client authentication, contact DHCS via the Support Center.

For the OAuth authorization code, refresh token, and token-exchange semantics, see the EIAM authorization server documentation. Those flows are owned by EIAM and are the same regardless of TPA registration status.


Registration Walkthrough (Steps 1 Through 3)

The registration wizard is a three-step form reachable from the Third-Party App Developer persona tile on the Home page (leads to /tpaRegister). Selecting Start registration enters Step 1. You can leave the wizard at any time via Cancel and pick up later via View current registrations.

Step 1: App Metadata

Provide the fields that identify your application to end users and to DHCS compliance staff:

  • Application name (required): the name shown to patients on the OAuth consent screen. Also used to compose your client_id (format: tpa-<app-name-kebab-case>-<8-alphanumeric>), so pick something stable.
  • Logo URI (optional): HTTPS URL of your application logo displayed on the consent screen.
  • Privacy policy URL (required): HTTPS URL of your public privacy policy.
  • Terms of service URL (optional): HTTPS URL of your terms of service.
  • Organization name (optional): the entity behind the application.
  • Organization contact email (required): where DHCS reaches you for compliance or operational questions.
  • Redirect URI (one or more): HTTPS URLs where the OAuth authorization server sends users after login. Each must be an exact match to what your application will use; wildcards are not permitted.

Select Next to advance to Step 2. Validation errors surface inline next to each field.

Step 2: Technical Details & Attestation

Choose your FHIR client type (Confidential or Public; see the section above) and read the attestation checkbox carefully:

“I attest that this application will comply with all applicable privacy regulations and data-use obligations, will not re-disclose patient data beyond the scope of patient authorization, and will honor patient-initiated revocations of access.”

Selecting the checkbox is required. Then select Validate & Register. The portal validates every field, ensures redirect URIs use HTTPS, and submits the registration. Back returns to Step 1 without losing entered data.

On success, you advance to Step 3.

Step 3: Select an API to Request Access

Pick the first API you want your application to access. Each API tile shows the API name, a short description, and a Request access button. Selecting Request access opens the per-API confirmation modal; see the next section.

If you want to complete registration without immediately requesting API access, select Finish for now. You can add API access later from your Registration Status page. Note: no client credentials are provisioned until you confirm your first per-API access request. This is intentional. Credentials are per-API, and provisioning is deferred to the first confirmation.


Requesting Access to a Specific API

Whether you're finishing registration or coming back later, per-API access happens on the API detail page. On any API detail page with TPA registration enabled, the callout in the header shows two options for developers who are already registered:

  • Request Access opens the per-API confirmation modal for a signed-in, registered developer.
  • New here? Register as a Third-Party Developer first sends unregistered developers to the wizard.

In the confirmation modal, select the OAuth scopes your application needs (multi-select), then Confirm. On success, the modal reveals your client_id and client_secret (Confidential clients) or client_id only (Public clients). This is the only time the secret is displayed in plain text. Use the Copy Client ID and Copy Client Secret actions to save them to your secret store immediately.

Select View registration status to see your registration overview, or Done to return to the API catalog.

For OAuth token requests, redirect URI handling, and JWT authentication details, see JWT Authentication with an API.


Rotating a Credential in Place

Credentials are rotated per-API from your Registration Status page (/tpaRegister/registrations/{registrationId}, or via View current registrations). Each active credential row shows a Rotate action.

Selecting Rotate opens a consequence-first confirmation dialog. On confirmation:

  1. The current client_secret is immediately invalidated — there is no grace period or overlap window.
  2. A new client_secret is provisioned and revealed once via the credential reveal modal. Copy it to your secret store now.
  3. The client_id does not change, and your existing granted scopes are unaffected.

Your integration will stop working until you deploy the new secret. If you need to stage the cutover without downtime, use Request additional credential instead (see the section below).

When to rotate: on a scheduled cadence appropriate to your risk posture (annually at minimum for confidential clients), or immediately if you suspect the current secret has been exposed.

Rotate is available only for Confidential clients. Public (PKCE) clients have no client_secret to rotate.


Requesting an Additional Credential Pair

Use Request additional credential when you need to stage a zero-downtime credential replacement — provisioning a second, independent client_id/client_secret pair so you can cut your application over before invalidating the original.

The Request additional credential button appears on each API row of your Registration Status page's Client Credentials table whenever that row has exactly one Active credential.

Selecting Request additional credential:

  1. Provisions a new, independent client_id/client_secret pair for that same API association, inheriting the association's existing granted scopes.
  2. Reveals the new secret once via the credential reveal modal — copy it to your secret store immediately.
  3. Leaves the original credential fully Active and usable. No cutover happens automatically.

After provisioning, both credentials authenticate independently. To complete a staged rotation:

  1. Deploy the new client_id/client_secret to your application and verify it works.
  2. Once fully cut over, click Revoke on the old credential's row to permanently invalidate it.

Credential cap: each API association supports at most two concurrently Active credentials. When the cap is reached, Request additional credential is disabled with an explanatory tooltip. Revoke one credential before requesting another.

Confidential clients only. Public (PKCE) clients have no client_secret, so additional credential provisioning is not available for them.


Revoking an Individual Credential

Use the Revoke button on a credential row to permanently invalidate that one client_id/client_secret without touching the rest of your registration.

Selecting Revoke opens a consequence-first confirmation dialog. On confirmation, the credential's client_id and client_secret are permanently invalidated and access to that API ends immediately for any application still using them. The revocation cannot be undone.

The most common reason to revoke a single credential is completing a staged rotation: after you have used Request additional credential (see the section above) to provision a second pair and confirmed your application is fully cut over to it, click Revoke on the old credential's row to close out the original.

Per-credential Revoke is distinct from Revoke Registration (the Danger Zone action at the bottom of the page), which invalidates the entire registration and all of its credentials at once. Use per-row Revoke when you only want to retire one specific credential.


Self-Revoking the Entire Registration

At the bottom of your Registration Status page there is a Revoke Registration action. Selecting it opens a confirmation modal. On confirmation:

  • The registration transitions to Revoked status.
  • All active credentials associated with the registration are invalidated immediately.
  • The associated client_id values continue to exist for audit purposes but no longer authenticate.
  • Patient tokens issued under this registration are revoked at the OAuth authorization server (owned by EIAM). Patients whose data your application had access to are automatically informed via the standard EIAM revocation notification path.

Self-revocation is permanent. If you need to restart, you must register again with a new client_id. If you want to temporarily disable an integration without permanent revocation, contact the Support Center. A DHCS admin can suspend the registration (see the section below), which is reversible.

To revoke one credential without revoking the whole registration, use the Revoke action on that credential's row instead of Revoke Registration.


Understanding Suspension (DHCS-Initiated)

Separate from developer-initiated self-revocation (see above), DHCS reserves the right to suspend a TPA registration in response to a policy violation, compliance concern, or security incident. A suspended registration:

  • Shows Suspended status on your Registration Status page.
  • Cannot authenticate any new tokens until DHCS lifts the suspension.
  • Retains all its credentials and API associations. Nothing is deleted.
  • Notifies the organization contact email (from Step 1 of the wizard) when the suspension is applied and again when it is lifted.

Suspension is intended as a temporary control while DHCS investigates. If you believe a suspension was applied in error, respond to the notification email or submit a support request. Do not attempt to register the same application under a new client_id to work around the suspension.

If suspension turns into permanent removal, the registration transitions to Revoked by DHCS-side action, and the outcome is the same as developer-initiated self-revocation described above.


Troubleshooting Common Validation Errors

The wizard surfaces validation errors inline next to each field. Common cases and what to check:

“Application name is required”: fill in Step 1's Application name field. This value is also used to generate your client_id, so choose it deliberately.

“Application name contains characters that cannot be slugified”: after slugification (lowercase, non-alphanumeric to -, collapse duplicates), your app name must produce at least one alphanumeric character. Names composed entirely of punctuation or non-ASCII characters fail this check. Include at least one ASCII letter or digit.

“Privacy policy URL is not a valid HTTPS URL”: URL must start with https:// and be well-formed. http:// URLs are rejected. Check for typos in the scheme.

“Redirect URI is not a valid HTTPS URL”: same rule as above, applied to each redirect URI. Each URI must be an exact match to a URL your application will use. No wildcards, no path templating.

“Organization contact email is not a valid email address”: must contain a single @ and a well-formed domain.

“Attestation must be accepted”: select the checkbox on Step 2 before selecting Validate & Register.

“Unable to reach the redirect URI to verify it is a live endpoint”: DHCS validates that redirect URIs are reachable. If your app is still in development and the URI is not yet publicly resolvable, deploy at least a minimal endpoint (a static page returning 200 OK is sufficient for the reachability check) before completing registration.

Errors on Step 3 during “Request access” confirmation: most likely the OAuth scopes you selected are not permitted on that API. Review the API's Swagger documentation for its published scope list and try again.

“Registration failed with an internal error, please try again”: transient backend failure. Retry once. If the error persists, submit a support request via the Support Center link in the footer with your Application name and the approximate timestamp of the failure.

For runtime errors (401, 403, 429) after credentials are provisioned, see API Troubleshooting for Consumers.