SMART: Asymmetric (“private key JWT”) authentication

Aidbox supports SMART Asymmetric Private Key JWT Authentication to securely manage client authentication.

JWKS

When registering with a FHIR authorization server, the client should provide its public key for authentication. This key should be included in a JSON Web Key (JWK) format within a JWK Set (JWKS).

Key Requirements for JWKs:

No matter how a JWK Set is communicated to the Aidbox FHIR authorization server, each JWK shall represent an asymmetric key by including the kty and kid properties, with content conveyed using “bare key” properties (i.e., direct base64 encoding of key material as integer values). Specifically:

  • For RSA public keys:

    • Each JWK shall include the n (modulus) and e (exponent) properties.

    • Each JWK shall include the crv (curve), x (x-coordinate), and y (y-coordinate) properties.

Aidbox provides JWKS endpoint with RSA public key.

GET /.well-known/jwks.json

So you can use Aidbox's JWKS or your own.

Registering Client

Before a SMART client can run against a FHIR server, the client SHALL generate or obtain an asymmetric key pair and register its public key set as jsks_uri in Client resource. Aidbox provides .well-known/jwks.json endpoint so you can use it.

PUT /Client/inferno-my-clinic-bulk-client
content-type: application/json
accept: application/json

{
  "type": "bulk-api-client",
  "active": true,
  "auth": {
    "client_credentials": {
      "client_assertion_types": [
        "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
      ],
      "access_token_expiration": 300,
      "token_format": "jwt"
    }
  },
  "scope": [
    "system/*.read"
  ],
  "jwks_uri": "<AIDBOX_BASE_URL>/.well-known/jwks.json",
  "grant_types": [
    "client_credentials"
  ]
}

Authenticating to the Token endpoint

Once the client generates an authentication JWT, it requests an access token based on either the SMART App Launch or SMART Backend Services specifications. The authentication details are included using these additional properties in the token request:

Authentication JWT Header Values:

Header Value
Description

alg *

Fixed value - RS384

kid *

The identifier for the key pair used to sign this JWT must be unique within the client's JWK Set.

typ *

Fixed value: JWT.

jku

The TLS-protected URL to the JWK Set that contains the public key(s) accessible without authentication or authorization. When present, this shall match the Client.jwks_uri value.

*- required value

Authentication JWT Claims:

Claim
Description

iss *

Client ID (issuer).

sub *

Client ID (subject).

aud *

Token endpoint URL - <AIDBOX_BASE_URL>/auth/token.

exp *

The expiration time for this authentication JWT is an integer, representing the number of seconds since the "Epoch" (1970-01-01T00:00:00Z UTC). This value must not exceed five minutes into the future.

jti *

Unique token identifier to prevent replay attacks.

*- required value

Example

JWT:

eyJhbGciOiJSUzM4NCIsImtpZCI6ImI0MTUyOGI2ZjM3YTk1MDBlZGI4YTkwNWE1OTViZGQ3IiwidHlwIjoiSldUIn0.eyJpc3MiOiJpbmZlcm5vLW15LWNsaW5pYy1idWxrLWNsaWVudCIsInN1YiI6ImluZmVybm8tbXktY2xpbmljLWJ1bGstY2xpZW50IiwiYXVkIjoiaHR0cHM6Ly9nMTB0ZXN0LmVkZ2UuYWlkYm94LmFwcC9hdXRoL3Rva2VuIiwiZXhwIjoxNzM0MDA5NjI2LCJqdGkiOiJkZGI4NzQ5OTk1YjFkNWRiNDVkNTQ2NDVmZmU0ZmExZTkxODRhODI3YjlmOWM5MDY5ZDQxYzRmYjJhNjBjYTY3In0.hxKAec655NTH7Gs6qy2Cz2CXvETWnxF0jydjEdXNKYyrQvecBWct_ITc92eFiDnZ5jubhExqojeE2HUDn3lmS89Q9qFfGEsByLWXy4nJqSHa2y5mWxD5aI3LF3c4oSOZXSj-jFxAlSmxhV7MxumnJ2XP-6e81QQT-QQ9mDomWhgrIjqaHhv5yPQzI6CqDad9XBInMcE7S_TZ9QTpq3WtzC520-8SH3KdVF9dILO6pBGOOrlZ8468Vwfl5WL6XuhhwjbIIp8B5F0qAOGIGiA8V_-eE6PM1CNZtKQfrZNvVh0VwSu4T2k3gL4ZfI_8nhpUt8EEusOsu_6EvK3sP1yv7w

JWT's parsed headers:

{
  "alg": "RS384",
  "kid": "b41528b6f37a9500edb8a905a595bdd7",
  "typ": "JWT"
}

JWT's parsed claims:

{
  "iss": "inferno-my-clinic-bulk-client",
  "sub": "inferno-my-clinic-bulk-client",
  "aud": "https://g10test.edge.aidbox.app/auth/token",
  "exp": 1734009626,
  "jti": "ddb8749995b1d5db45d54645ffe4fa1e9184a827b9f9c9069d41c4fb2a60ca67"
}

Requesting an Access Token

This JWT should be used as client_assertion a parameter in the access token request. See the full example in SMART Backend services.

Last updated