SMART Permission Tickets
0.1.0 - ci-build
SMART Permission Tickets, published by . This guide is not an authorized publication; it is the continuous build for version 0.1.0 built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/jmandel/smart-permission-tickets-wip/ and changes regularly. See the Directory of published versions
| Official URL: http://smarthealthit.org/ig/permission-tickets/ImplementationGuide/smart.permission-tickets | Version: 0.1.0 | |||
| Draft as of 2026-02-09 | Computable Name: SmartPermissionTickets | |||
Enabling Granular, Context-Aware Authorization in Health Networks
Current interoperability standards and frameworks (SMART on FHIR, TEFCA) face a "granularity gap." Authorization flows effectively force a choice between two extremes:
Permission Tickets solve this by introducing a Capability-Based Access Control model to OAuth. Instead of the Data Holder asking, "Who are you and what is your pre-configured role?", it asks, "What proof do you hold that authorizes this specific request?"
A Permission Ticket is a portable, cryptographically signed artifact. It uses standard FHIR Resources as data models to describe the Subject (Patient), the Actor (Requesting Agent), and the Context (Trigger Event), enabling precise access control without requiring realtime user interaction at the data source.
In standard SMART flows, if a patient wants to aggregate their data from five different hospitals into a personal health app, they must locate five different portals, remember five usernames/passwords, and click "Approve" five times. This friction destroys adoption. Furthermore, the scopes are coarse; a user can usually only say "Yes" to everything or "No" to everything.
In B2B flows (like TEFCA Treatment or Payer exchange), Client Apps authenticate via certificates. Because it is too hard to configure specific permissions for every patient and every external partner, Data Holders often default to binary trust: if the partner is a "Trusted Node," they get access to the firehose. This is unacceptable for sensitive use cases like Research, Public Health, or Social Care.
A Permission Ticket is a JWT minted by a Trusted Issuer. It acts as a self-contained authorization grant.
Patient, PractitionerRole, Organization) to define identities, making integration with existing EHR logic seamless.sequenceDiagram
participant Trigger as Trigger Event
participant Issuer as Trusted Issuer
participant Client as Client App
participant Server as Data Holder (FHIR)
Note over Trigger, Client: 1. Context Established
Trigger->>Issuer: Event (e.g. Referral, Case Report)
Issuer->>Issuer: Verify Context & Identity
Issuer->>Client: Mint Permission Ticket (JWT)
Note over Client, Server: 2. Redemption
Client->>Client: Generate Client Assertion (JWT)
Client->>Client: Embed Ticket in Assertion
Client->>Server: POST /token (client_credentials + assertion)
Note over Server: 3. Validation
Server->>Server: Verify Client Signature
Server->>Server: Verify Ticket Signature (Issuer Trust)
Server->>Server: Enforce Ticket Constraints
Server-->>Client: Access Token (Down-scoped)
Note over Client, Server: 4. Access
Client->>Server: GET /Patient/123/Immunization
Server-->>Client: FHIR Resources
This architecture is a strict profile of SMART Backend Services (which itself profiles RFC 7523).
The key difference is the payload of the client_assertion. In standard SMART Backend Services, the assertion proves the client's identity. In this architecture, the assertion also carries the Permission Tickets in a dedicated permission_tickets claim. Permission Tickets extend authorization context only; they do not alter SMART Backend Services client authentication requirements.
trust_chain in the header of its client_assertion, allowing the Authorization Server to verify the client's metadata and trust status dynamically.https://app.example.com).trust_chain in their assertion. This allows Data Holders to verify the client's legitimacy via a common Trust Anchor without requiring manual pre-registration of every client.The Request:
POST /token HTTP/1.1
Host: fhir.hospital.com
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=eyJhbGciOiJ... (Signed JWT containing tickets and trust_chain)
&scope=patient/Observation.rs
Here is what the client_assertion looks like when decoded. Note the trust_chain for automatic registration and the embedded ticket_context.
{
"alg": "ES256",
"kid": "nvOGRCsTz2QIQLsbl0ZQ_ux0tfyh5iave-jvNsANWv8",
"trust_chain": [
"eyJhbGciOiJFUzI1NiIs... (Signed Entity Statement for Client)",
"eyJhbGciOiJFUzI1NiIs... (Signed Entity Statement for Intermediate)",
"eyJhbGciOiJFUzI1NiIs... (Signed Entity Statement for Trust Anchor)"
]
}
{
"iss": "https://app.client.id",
"sub": "https://app.client.id",
"aud": "https://network.org/token",
"jti": "assertion-jti-123",
"iat": 1770664341,
"exp": 1770664641,
"permission_ticket_profile": "https://smarthealthit.org/permission-ticket-profile/network-patient-access-v1",
"permission_tickets": [
"eyJhbGciOiJFUzI1NiIsImtpZCI6Im52T0dSQ3NUejJRSVFMc2JsMFpRX3V4MHRmeWg1aWF2ZS1qdk5zQU5XdjgifQ.eyJpc3MiOiJodHRwczovL3RydXN0LWJyb2tlci5vcmciLCJzdWIiOiJodHRwczovL2FwcC5jbGllbnQuaWQiLCJhdWQiOiJodHRwczovL25ldHdvcmsub3JnIiwiZXhwIjoxNzcwNjY3OTQxLCJ0aWNrZXRfdHlwZSI6Imh0dHBzOi8vc21hcnRoZWFsdGhpdC5vcmcvcGVybWlzc2lvbi10aWNrZXQtdHlwZS9uZXR3b3JrLXBhdGllbnQtYWNjZXNzLXYxIiwiY2xpZW50X2JpbmRpbmciOnsiandrc191cmkiOiJodHRwczovL2FwcC5jbGllbnQuaWQvandrcy5qc29uIn0sInRpY2tldF9jb250ZXh0Ijp7InN1YmplY3QiOnsicmVzb3VyY2VUeXBlIjoiUGF0aWVudCIsImlkIjoiMTIzIn0sImNhcGFiaWxpdHkiOnsic2NvcGVzIjpbInBhdGllbnQvKi5ycyJdfX0sImlhdCI6MTc3MDY2NDM0MX0.Jdau4QCxxdo-PbdmFyjdrIFg7pWxHOYY5Dkvesxiv39MJKysuCwYx1pcS1fSCBWz5gqttW_r1TpzSP_kOdlriQ"
]
}
eyJhbGciOiJFUzI1NiIsImtpZCI6Im52T0dSQ3NUejJRSVFMc2JsMFpRX3V4MHRmeWg1aWF2ZS1qdk5zQU5XdjgiLCJ0cnVzdF9jaGFpbiI6WyJleUpoYkdjaU9pSkZVekkxTmlJcy4uLiAoU2lnbmVkIEVudGl0eSBTdGF0ZW1lbnQgZm9yIENsaWVudCkiLCJleUpoYkdjaU9pSkZVekkxTmlJcy4uLiAoU2lnbmVkIEVudGl0eSBTdGF0ZW1lbnQgZm9yIEludGVybWVkaWF0ZSkiLCJleUpoYkdjaU9pSkZVekkxTmlJcy4uLiAoU2lnbmVkIEVudGl0eSBTdGF0ZW1lbnQgZm9yIFRydXN0IEFuY2hvcikiXX0.eyJpc3MiOiJodHRwczovL2FwcC5jbGllbnQuaWQiLCJzdWIiOiJodHRwczovL2FwcC5jbGllbnQuaWQiLCJhdWQiOiJodHRwczovL25ldHdvcmsub3JnL3Rva2VuIiwianRpIjoiYXNzZXJ0aW9uLWp0aS0xMjMiLCJpYXQiOjE3NzA2NjQzNDEsImV4cCI6MTc3MDY2NDY0MSwicGVybWlzc2lvbl90aWNrZXRfcHJvZmlsZSI6Imh0dHBzOi8vc21hcnRoZWFsdGhpdC5vcmcvcGVybWlzc2lvbi10aWNrZXQtcHJvZmlsZS9uZXR3b3JrLXBhdGllbnQtYWNjZXNzLXYxIiwicGVybWlzc2lvbl90aWNrZXRzIjpbImV5SmhiR2NpT2lKRlV6STFOaUlzSW10cFpDSTZJbTUyVDBkU1EzTlVlakpSU1ZGTWMySnNNRnBSWDNWNE1IUm1lV2cxYVdGMlpTMXFkazV6UVU1WGRqZ2lmUS5leUpwYzNNaU9pSm9kSFJ3Y3pvdkwzUnlkWE4wTFdKeWIydGxjaTV2Y21jaUxDSnpkV0lpT2lKb2RIUndjem92TDJGd2NDNWpiR2xsYm5RdWFXUWlMQ0poZFdRaU9pSm9kSFJ3Y3pvdkwyNWxkSGR2Y21zdWIzSm5JaXdpWlhod0lqb3hOemN3TmpZM09UUXhMQ0owYVdOclpYUmZkSGx3WlNJNkltaDBkSEJ6T2k4dmMyMWhjblJvWldGc2RHaHBkQzV2Y21jdmNHVnliV2x6YzJsdmJpMTBhV05yWlhRdGRIbHdaUzl1WlhSM2IzSnJMWEJoZEdsbGJuUXRZV05qWlhOekxYWXhJaXdpWTJ4cFpXNTBYMkpwYm1ScGJtY2lPbnNpYW5kcmMxOTFjbWtpT2lKb2RIUndjem92TDJGd2NDNWpiR2xsYm5RdWFXUXZhbmRyY3k1cWMyOXVJbjBzSW5ScFkydGxkRjlqYjI1MFpYaDBJanA3SW5OMVltcGxZM1FpT25zaWNtVnpiM1Z5WTJWVWVYQmxJam9pVUdGMGFXVnVkQ0lzSW1sa0lqb2lNVEl6SW4wc0ltTmhjR0ZpYVd4cGRIa2lPbnNpYzJOdmNHVnpJanBiSW5CaGRHbGxiblF2S2k1eWN5SmRmWDBzSW1saGRDSTZNVGMzTURZMk5ETTBNWDAuSmRhdTRRQ3h4ZG8tUGJkbUZ5amRySUZnN3BXeEhPWVk1RGt2ZXN4aXYzOU1KS3lzdUN3WXgxcGNTMWZTQ0JXejVncXR0V19yMVRwelNQX2tPZGxyaVEiXX0._1lawFb547PIQRwKhBU-rs5k9m2Wu-gTPjibtR-bdZjGrR7tAh3Hk3KL_FxcPulI3a-pVdGAXC_0B4mRZmsDSg
The ticket payload is a JWT. It wraps standard FHIR JSON objects within a ticket_context claim.
{
"iss": "https://trust-broker.org",
"sub": "issuer-defined-subject",
"aud": "https://network.org",
"exp": 1735689600,
"ticket_type": "https://smarthealthit.org/permission-ticket-type/proxy-v1",
"client_binding": {
"jwks_uri": "https://app.client.id/jwks.json"
},
"ticket_context": {
"subject": {
"resourceType": "Patient"
},
"actor": {
"resourceType": "PractitionerRole"
},
"context": {
"type": {
"system": "http://terminology.hl7.org/CodeSystem/v3-ActReason",
"code": "REFER"
},
"focus": {
"system": "http://snomed.info/sct",
"code": "49436004",
"display": "Atrial fibrillation"
},
"identifier": [
{
"system": "https://issuer.org/cases",
"value": "CASE-123"
}
]
},
"capability": {
"scopes": [
"patient/*.rs"
]
}
}
}
See the Logical Model for formal definitions.
Each Permission Ticket SHALL bind redemption to a client key set using client_binding:
client_binding.jwks_uri: HTTPS JWKS URLclient_binding.jwks: embedded JWK SetExactly one of jwks_uri or jwks SHALL be present.
At token processing time, the Data Holder SHALL validate that the JWK used to verify the client_assertion signature is a member of the ticket-bound key set. If jku is present in the client_assertion header and client_binding.jwks_uri is present in the ticket, the two values SHALL be identical.
The Data Holder SHALL perform a two-layer validation:
client_assertion signature using the Client's registered public key (JWK).permission_tickets array from the assertion.permission_ticket_profile from the assertion and select profile processing rules.iss (Trust Broker) public key.iss in the Data Holder's trusted list?ticket_type SHALL be present and recognized in the declared profile. For single-ticket profiles, ticket_type MAY be omitted; if present, it SHALL match the profile's required type.client_assertion signing key match the ticket client_binding key set?ticket_context.capability rules.The Data Holder calculates granted access through the intersection of:
scope parameter in the token requestticket_context.capabilityIf the intersection yields no valid access, return invalid_scope error.
Requested scopes SHALL use SMART scope grammar. This specification allows either patient/* or system/* scopes depending on profile. For single-patient Permission Ticket profiles, clients SHOULD request SMART v2 CRUDS suffix scopes (for example, patient/Observation.rs).
The capability object defines what access the ticket authorizes:
| Field | Type | Description |
|---|---|---|
scopes |
string[] | SMART scopes (e.g., patient/*.rs). Wildcard scopes expand to match specific requests. |
periods |
Period[] | Time restrictions. Data Holder SHALL filter results to resources with relevant dates within these periods. |
locations |
Address[] | Jurisdictional restrictions at state granularity. If present, Data Holder SHALL limit results to data from matching jurisdictions. |
organizations |
Organization[] | Source restrictions. If present, Data Holder SHALL limit results to data from matching organizations (by identifier or name). |
Constraint Semantics:
invalid_grant and error_description indicating the unsupported constraintExample Capability:
{
"capability": {
"scopes": [
"patient/Condition.rs",
"patient/Procedure.rs"
],
"periods": [
{
"start": "2023-01-01",
"end": "2024-12-31"
}
],
"locations": [
{
"state": "CA"
},
{
"state": "NY"
}
],
"organizations": [
{
"identifier": [
{
"system": "http://hl7.org/fhir/sid/us-npi",
"value": "1234567890"
}
]
}
]
}
}
This ticket authorizes read access to Conditions and Procedures, but only for data:
A client MAY present multiple tickets in the permission_tickets array to compose authorization from multiple sources.
Multi-ticket scenarios are defined by use case profiles. Each profile specifies:
For the current single-ticket catalog in this specification, use case and profile are 1:1:
| Use Case | Profile URI | Canonical ticket_type URI |
|---|---|---|
| Use Case 1: Network-Mediated Patient Access | https://smarthealthit.org/permission-ticket-profile/network-patient-access-v1 | https://smarthealthit.org/permission-ticket-type/network-patient-access-v1 |
| Use Case 2: Authorized Representative (Proxy) | https://smarthealthit.org/permission-ticket-profile/authorized-representative-v1 | https://smarthealthit.org/permission-ticket-type/authorized-representative-v1 |
| Use Case 3: Public Health Investigation | https://smarthealthit.org/permission-ticket-profile/public-health-investigation-v1 | https://smarthealthit.org/permission-ticket-type/public-health-investigation-v1 |
| Use Case 4: Social Care (CBO) Referral | https://smarthealthit.org/permission-ticket-profile/social-care-referral-v1 | https://smarthealthit.org/permission-ticket-type/social-care-referral-v1 |
| Use Case 5: Payer Claims Adjudication | https://smarthealthit.org/permission-ticket-profile/payer-claims-adjudication-v1 | https://smarthealthit.org/permission-ticket-type/payer-claims-adjudication-v1 |
| Use Case 6: Research Study | https://smarthealthit.org/permission-ticket-profile/research-study-v1 | https://smarthealthit.org/permission-ticket-type/research-study-v1 |
| Use Case 7: Provider-to-Provider Consult | https://smarthealthit.org/permission-ticket-profile/provider-consult-v1 | https://smarthealthit.org/permission-ticket-type/provider-consult-v1 |
The client SHALL assert the profile in the client_assertion claim:
{
"permission_ticket_profile": "https://smarthealthit.org/permission-ticket-profile/proxy-v1"
}
permission_ticket_profile is the primary processing selector in client_assertion.
ticket_type is a field inside each Permission Ticket artifact. For single-ticket profiles, ticket_type MAY be omitted; if present, it SHALL match the profile's required type. For multi-ticket profiles, each ticket SHALL include ticket_type and it SHALL match one of the profile's allowed ticket types.
Unknown profile, unknown ticket type (when required), or profile/type mismatch SHALL be rejected with invalid_grant.
Profile: Identity + Designated Representative
Two tickets are required:
actor identitysubject, capability, and a reference linking to the actorTicket 1 (Identity Provider - e.g., Clear):
{
"iss": "https://clear.me",
"sub": "clear-subject-789",
"aud": "https://tefca.hhs.gov",
"exp": 1735689600,
"ticket_type": "https://smarthealthit.org/permission-ticket-type/identity-v1",
"client_binding": {
"jwks_uri": "https://health-app.example.com/jwks.json"
},
"ticket_context": {
"actor": {
"resourceType": "RelatedPerson",
"identifier": [
{
"system": "https://clear.me/id",
"value": "CLR-789"
}
],
"name": [
{
"family": "Smith",
"given": [
"Jane"
]
}
]
}
}
}
Ticket 2 (Trust Broker):
{
"iss": "https://trust-broker.org",
"sub": "trust-subject-456",
"aud": "https://tefca.hhs.gov",
"exp": 1735689600,
"ticket_type": "https://smarthealthit.org/permission-ticket-type/authorization-v1",
"client_binding": {
"jwks_uri": "https://health-app.example.com/jwks.json"
},
"ticket_context": {
"subject": {
"type": "match",
"traits": {
"resourceType": "Patient"
}
},
"context": {
"type": {
"code": "DPOA"
},
"actor_reference": "https://clear.me/id|CLR-789"
},
"capability": {
"scopes": [
"patient/*.rs"
]
}
}
}
The Data Holder, implementing this profile:
actor_reference in Ticket 2 matches the actor.identifier in Ticket 1Profile: Base + Sensitive Category
A network-level ticket provides baseline access; an additional ticket from a specialized authority grants access to sensitive categories (e.g., behavioral health, substance use).
Regardless of profile, these rules always apply:
client_assertion signing key SHALL satisfy each ticket client_bindingpermission_ticket_profile rulesaud) ValidationThe aud claim specifies where the ticket is valid. Two modes are supported:
aud for Permission Tickets is intentionally broader than aud in client_assertion (which remains the token endpoint per SMART Backend Services).
The aud is a specific URL or array of URLs:
{ "aud": "https://fhir.hospital.com" }
// or
{ "aud": ["https://fhir.hospital-a.com", "https://fhir.hospital-b.com"] }
Validation: The Data Holder's base URL SHALL exactly match one of the enumerated values.
The aud references a trust framework identifier:
{ "aud": "https://tefca.hhs.gov" }
Validation: The Data Holder SHALL be a verified participant in the referenced trust framework. Verification mechanisms are trust-framework-specific (e.g., the Data Holder's Entity ID appears in the framework's federation).
| Scenario | Recommended aud |
|---|---|
| Ticket for known single recipient | Specific Data Holder URL |
| Ticket valid across a network | Trust framework identifier |
| Ticket for multiple known recipients | Array of Data Holder URLs |
Data Holders SHALL reject tickets where aud validation fails with error invalid_grant and error_description: "Ticket audience mismatch".
exp (expiration) claim| Use Case | Recommended exp |
|---|---|
| Interactive/real-time | 1-4 hours |
| Batch processing | 24 hours |
| Standing authorization | Up to 1 year (with revocation) |
For scenarios requiring access beyond a single session (e.g., ongoing care relationships, research studies), two approaches are supported:
Approach 1: Refresh via Issuer
The client periodically obtains fresh tickets from the issuer. Suitable when:
Approach 2: Long-Lived Tickets with Revocation
The issuer mints a ticket with extended validity (weeks to months) and supports revocation. Suitable when:
Issuers MAY support revocation of individual tickets before expiration.
Revocation Identifier
Tickets supporting revocation include a revocation claim:
{
"iss": "https://trust-broker.org",
"sub": "issuer-defined-subject",
"aud": "https://tefca.hhs.gov",
"exp": 1735689600,
"ticket_type": "https://smarthealthit.org/permission-ticket-type/proxy-v1",
"client_binding": {
"jwks_uri": "https://app.example.com/jwks.json"
},
"jti": "ticket-unique-id",
"revocation": {
"url": "https://trust-broker.org/.well-known/crl/patient-access.json",
"rid": "abc123xyz"
},
"ticket_context": {
"subject": {
"resourceType": "Patient"
},
"capability": {
"scopes": [
"patient/*.rs"
]
}
}
}
| Field | Description |
|---|---|
revocation.url |
URL of the issuer's Credential Revocation List (CRL) for this category of tickets |
revocation.rid |
Revocation identifier for this ticket. SHALL be opaque (not contain PII). |
Generating rid: Issuers SHOULD use a one-way transformation to prevent correlation:
rid = base64url(hmac-sha-256(issuer_secret || kid, ticket_jti)[0:8])
Revocation List Format
The CRL is a JSON file served at the URL specified in the ticket:
{
"kid": "issuer-signing-key-id",
"method": "rid",
"ctr": 42,
"rids": [
"abc123xyz",
"def456uvw.1710460800"
]
}
| Field | Description |
|---|---|
kid |
Key ID used to sign tickets covered by this CRL |
method |
Revocation method identifier. Value "rid" indicates the method defined in this specification. |
ctr |
Monotonic counter incremented on each update. Verifiers use this to detect changes. |
rids |
Array of revoked rid values. Optional .timestamp suffix (Unix seconds) revokes only tickets issued before that time. |
Timestamp Suffix Example:
The entry "def456uvw.1710460800" revokes tickets with rid = def456uvw that were issued (iat) before March 15, 2024 00:00:00 UTC. Tickets with that rid issued after this timestamp remain valid.
Revocation Checking
Issuers:
ctr on every updateData Holders:
revocation is present in ticket, SHALL check the CRLrid appears in the CRL (respecting timestamp suffix if present)Grouping for Privacy
Issuers MAY use multiple CRL URLs to group tickets by category, preventing correlation across ticket types when checking revocation.
Here are seven scenarios demonstrating how FHIR resources are used to model diverse authorization needs.
A patient uses a high-assurance Digital ID wallet to authorize an app to fetch their data from multiple hospitals.
Patient (Matched by Demographics: Name, DOB, Identifier).scopes = patient/Immunization.rs, patient/AllergyIntolerance.rs.{
"alg": "ES256",
"kid": "nvOGRCsTz2QIQLsbl0ZQ_ux0tfyh5iave-jvNsANWv8"
}
{
"iss": "https://trust-broker.org",
"sub": "https://client-app.example.com/123",
"aud": "https://network.org",
"exp": 1770667941,
"ticket_type": "https://smarthealthit.org/permission-ticket-type/network-patient-access-v1",
"client_binding": {
"jwks_uri": "https://client-app.example.com/jwks.json"
},
"ticket_context": {
"subject": {
"type": "match",
"traits": {
"resourceType": "Patient",
"name": [
{
"family": "Smith",
"given": [
"John"
]
}
],
"birthDate": "1980-01-01"
}
},
"capability": {
"scopes": [
"patient/Immunization.rs",
"patient/AllergyIntolerance.rs"
]
}
},
"iat": 1770664341
}
eyJhbGciOiJFUzI1NiIsImtpZCI6Im52T0dSQ3NUejJRSVFMc2JsMFpRX3V4MHRmeWg1aWF2ZS1qdk5zQU5XdjgifQ.eyJpc3MiOiJodHRwczovL3RydXN0LWJyb2tlci5vcmciLCJzdWIiOiJodHRwczovL2NsaWVudC1hcHAuZXhhbXBsZS5jb20vMTIzIiwiYXVkIjoiaHR0cHM6Ly9uZXR3b3JrLm9yZyIsImV4cCI6MTc3MDY2Nzk0MSwidGlja2V0X3R5cGUiOiJodHRwczovL3NtYXJ0aGVhbHRoaXQub3JnL3Blcm1pc3Npb24tdGlja2V0LXR5cGUvbmV0d29yay1wYXRpZW50LWFjY2Vzcy12MSIsImNsaWVudF9iaW5kaW5nIjp7Imp3a3NfdXJpIjoiaHR0cHM6Ly9jbGllbnQtYXBwLmV4YW1wbGUuY29tL2p3a3MuanNvbiJ9LCJ0aWNrZXRfY29udGV4dCI6eyJzdWJqZWN0Ijp7InR5cGUiOiJtYXRjaCIsInRyYWl0cyI6eyJyZXNvdXJjZVR5cGUiOiJQYXRpZW50IiwibmFtZSI6W3siZmFtaWx5IjoiU21pdGgiLCJnaXZlbiI6WyJKb2huIl19XSwiYmlydGhEYXRlIjoiMTk4MC0wMS0wMSJ9fSwiY2FwYWJpbGl0eSI6eyJzY29wZXMiOlsicGF0aWVudC9JbW11bml6YXRpb24ucnMiLCJwYXRpZW50L0FsbGVyZ3lJbnRvbGVyYW5jZS5ycyJdfX0sImlhdCI6MTc3MDY2NDM0MX0.mYLFbJYZKZmT_KvvJztwtvLLm5pOO-seEcihWhkh045Tw2wJMupBBojkGgbOS03cgCaBDC58Ng71-0iN9UWG3w
An adult daughter accesses her elderly mother's records. The relationship is verified by a Trust Broker, not the Hospital.
Patient (Matched by Identifier).RelatedPerson (Name, Telecom, Relationship Code).scopes = patient/*.rs.{
"alg": "ES256",
"kid": "nvOGRCsTz2QIQLsbl0ZQ_ux0tfyh5iave-jvNsANWv8"
}
{
"iss": "https://trust-broker.org",
"sub": "https://client-app.example.com/456",
"aud": "https://network.org",
"exp": 1770667941,
"ticket_type": "https://smarthealthit.org/permission-ticket-type/authorized-representative-v1",
"client_binding": {
"jwks_uri": "https://client-app.example.com/jwks.json"
},
"ticket_context": {
"subject": {
"resourceType": "Patient",
"identifier": [
{
"system": "https://national-mpi.net",
"value": "pt-555"
}
]
},
"actor": {
"resourceType": "RelatedPerson",
"name": [
{
"family": "Doe",
"given": [
"Jane"
]
}
],
"telecom": [
{
"system": "email",
"value": "jane.doe@example.com"
}
],
"relationship": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode",
"code": "DAU",
"display": "Daughter"
}
]
}
]
},
"capability": {
"scopes": [
"patient/*.rs"
]
}
},
"iat": 1770664341
}
eyJhbGciOiJFUzI1NiIsImtpZCI6Im52T0dSQ3NUejJRSVFMc2JsMFpRX3V4MHRmeWg1aWF2ZS1qdk5zQU5XdjgifQ.eyJpc3MiOiJodHRwczovL3RydXN0LWJyb2tlci5vcmciLCJzdWIiOiJodHRwczovL2NsaWVudC1hcHAuZXhhbXBsZS5jb20vNDU2IiwiYXVkIjoiaHR0cHM6Ly9uZXR3b3JrLm9yZyIsImV4cCI6MTc3MDY2Nzk0MSwidGlja2V0X3R5cGUiOiJodHRwczovL3NtYXJ0aGVhbHRoaXQub3JnL3Blcm1pc3Npb24tdGlja2V0LXR5cGUvYXV0aG9yaXplZC1yZXByZXNlbnRhdGl2ZS12MSIsImNsaWVudF9iaW5kaW5nIjp7Imp3a3NfdXJpIjoiaHR0cHM6Ly9jbGllbnQtYXBwLmV4YW1wbGUuY29tL2p3a3MuanNvbiJ9LCJ0aWNrZXRfY29udGV4dCI6eyJzdWJqZWN0Ijp7InJlc291cmNlVHlwZSI6IlBhdGllbnQiLCJpZGVudGlmaWVyIjpbeyJzeXN0ZW0iOiJodHRwczovL25hdGlvbmFsLW1waS5uZXQiLCJ2YWx1ZSI6InB0LTU1NSJ9XX0sImFjdG9yIjp7InJlc291cmNlVHlwZSI6IlJlbGF0ZWRQZXJzb24iLCJuYW1lIjpbeyJmYW1pbHkiOiJEb2UiLCJnaXZlbiI6WyJKYW5lIl19XSwidGVsZWNvbSI6W3sic3lzdGVtIjoiZW1haWwiLCJ2YWx1ZSI6ImphbmUuZG9lQGV4YW1wbGUuY29tIn1dLCJyZWxhdGlvbnNoaXAiOlt7ImNvZGluZyI6W3sic3lzdGVtIjoiaHR0cDovL3Rlcm1pbm9sb2d5LmhsNy5vcmcvQ29kZVN5c3RlbS92My1Sb2xlQ29kZSIsImNvZGUiOiJEQVUiLCJkaXNwbGF5IjoiRGF1Z2h0ZXIifV19XX0sImNhcGFiaWxpdHkiOnsic2NvcGVzIjpbInBhdGllbnQvKi5ycyJdfX0sImlhdCI6MTc3MDY2NDM0MX0.--69TzkB0wEAUyOHzW2mhOQl8qc1kppodRGUC9C5v4-60R23F1e7pbpVACKYCG3ADByS3bboIn5bHypmtjOgmg
A Hospital creates a Case Report. The Public Health Agency (PHA) uses the report as a ticket to query for follow-up data.
Patient (Matched by Hospital ID).Organization (Name, Identifier, Type).type = PUBHLTH (Public Health), focus = Tuberculosis (SCT 56717001), identifier = Case ID.scopes = patient/*.rs, periods (Start Date).{
"alg": "ES256",
"kid": "nvOGRCsTz2QIQLsbl0ZQ_ux0tfyh5iave-jvNsANWv8"
}
{
"iss": "https://hospital-a.com",
"sub": "https://pha.gov/apps/report-client",
"aud": "https://hospital-a.com",
"exp": 1770667941,
"ticket_type": "https://smarthealthit.org/permission-ticket-type/public-health-investigation-v1",
"client_binding": {
"jwks_uri": "https://pha.gov/jwks.json"
},
"ticket_context": {
"subject": {
"resourceType": "Patient",
"id": "local-patient-123"
},
"actor": {
"resourceType": "Organization",
"name": "State Dept of Health",
"identifier": [
{
"system": "urn:ietf:rfc:3986",
"value": "https://doh.state.gov"
}
],
"type": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/organization-type",
"code": "govt"
}
]
}
]
},
"context": {
"type": {
"system": "http://terminology.hl7.org/CodeSystem/v3-ActReason",
"code": "PUBHLTH",
"display": "Public Health"
},
"focus": {
"system": "http://snomed.info/sct",
"code": "56717001",
"display": "Tuberculosis"
},
"identifier": [
{
"system": "https://doh.wa.gov/cases",
"value": "CASE-2024-999"
}
]
},
"capability": {
"scopes": [
"patient/*.rs"
],
"periods": [
{
"start": "2025-01-01",
"end": "2026-01-01"
}
]
}
},
"iat": 1770664341
}
eyJhbGciOiJFUzI1NiIsImtpZCI6Im52T0dSQ3NUejJRSVFMc2JsMFpRX3V4MHRmeWg1aWF2ZS1qdk5zQU5XdjgifQ.eyJpc3MiOiJodHRwczovL2hvc3BpdGFsLWEuY29tIiwic3ViIjoiaHR0cHM6Ly9waGEuZ292L2FwcHMvcmVwb3J0LWNsaWVudCIsImF1ZCI6Imh0dHBzOi8vaG9zcGl0YWwtYS5jb20iLCJleHAiOjE3NzA2Njc5NDEsInRpY2tldF90eXBlIjoiaHR0cHM6Ly9zbWFydGhlYWx0aGl0Lm9yZy9wZXJtaXNzaW9uLXRpY2tldC10eXBlL3B1YmxpYy1oZWFsdGgtaW52ZXN0aWdhdGlvbi12MSIsImNsaWVudF9iaW5kaW5nIjp7Imp3a3NfdXJpIjoiaHR0cHM6Ly9waGEuZ292L2p3a3MuanNvbiJ9LCJ0aWNrZXRfY29udGV4dCI6eyJzdWJqZWN0Ijp7InJlc291cmNlVHlwZSI6IlBhdGllbnQiLCJpZCI6ImxvY2FsLXBhdGllbnQtMTIzIn0sImFjdG9yIjp7InJlc291cmNlVHlwZSI6Ik9yZ2FuaXphdGlvbiIsIm5hbWUiOiJTdGF0ZSBEZXB0IG9mIEhlYWx0aCIsImlkZW50aWZpZXIiOlt7InN5c3RlbSI6InVybjppZXRmOnJmYzozOTg2IiwidmFsdWUiOiJodHRwczovL2RvaC5zdGF0ZS5nb3YifV0sInR5cGUiOlt7ImNvZGluZyI6W3sic3lzdGVtIjoiaHR0cDovL3Rlcm1pbm9sb2d5LmhsNy5vcmcvQ29kZVN5c3RlbS9vcmdhbml6YXRpb24tdHlwZSIsImNvZGUiOiJnb3Z0In1dfV19LCJjb250ZXh0Ijp7InR5cGUiOnsic3lzdGVtIjoiaHR0cDovL3Rlcm1pbm9sb2d5LmhsNy5vcmcvQ29kZVN5c3RlbS92My1BY3RSZWFzb24iLCJjb2RlIjoiUFVCSExUSCIsImRpc3BsYXkiOiJQdWJsaWMgSGVhbHRoIn0sImZvY3VzIjp7InN5c3RlbSI6Imh0dHA6Ly9zbm9tZWQuaW5mby9zY3QiLCJjb2RlIjoiNTY3MTcwMDEiLCJkaXNwbGF5IjoiVHViZXJjdWxvc2lzIn0sImlkZW50aWZpZXIiOlt7InN5c3RlbSI6Imh0dHBzOi8vZG9oLndhLmdvdi9jYXNlcyIsInZhbHVlIjoiQ0FTRS0yMDI0LTk5OSJ9XX0sImNhcGFiaWxpdHkiOnsic2NvcGVzIjpbInBhdGllbnQvKi5ycyJdLCJwZXJpb2RzIjpbeyJzdGFydCI6IjIwMjUtMDEtMDEiLCJlbmQiOiIyMDI2LTAxLTAxIn1dfX0sImlhdCI6MTc3MDY2NDM0MX0.UnsiPoimaAkjbwDQJiNIUGK24U0UWmCjTZJO73SjkKR3g1_0LtG52MLI4rufZXkXHumo2IqxEwyKRJAORhSmeA
A transactional/ad-hoc user. A Food Bank volunteer needs to update a referral status. She does not have an NPI or a user account.
Patient (Reference).PractitionerRole (Contained Practitioner + Organization).type = REFER (Referral), focus = Food insecurity (SCT 733423003).scopes = patient/ServiceRequest.rsu, patient/Task.rsu.{
"alg": "ES256",
"kid": "nvOGRCsTz2QIQLsbl0ZQ_ux0tfyh5iave-jvNsANWv8"
}
{
"iss": "https://referring-ehr.org",
"sub": "https://foodbank.org/apps/intake",
"aud": "https://referring-ehr.org",
"exp": 1770667941,
"ticket_type": "https://smarthealthit.org/permission-ticket-type/social-care-referral-v1",
"client_binding": {
"jwks_uri": "https://foodbank.org/jwks.json"
},
"ticket_context": {
"subject": {
"resourceType": "Patient",
"reference": "Patient/123"
},
"actor": {
"resourceType": "PractitionerRole",
"contained": [
{
"resourceType": "Practitioner",
"id": "p1",
"name": [
{
"family": "Volunteer",
"given": [
"Alice"
]
}
],
"telecom": [
{
"system": "email",
"value": "alice@foodbank.org"
}
]
},
{
"resourceType": "Organization",
"id": "o1",
"name": "Downtown Food Bank"
}
],
"practitioner": {
"reference": "#p1"
},
"organization": {
"reference": "#o1"
}
},
"context": {
"type": {
"system": "http://terminology.hl7.org/CodeSystem/v3-ActReason",
"code": "REFER",
"display": "Referral"
},
"focus": {
"system": "http://snomed.info/sct",
"code": "733423003",
"display": "Food insecurity"
}
},
"capability": {
"scopes": [
"patient/ServiceRequest.rsu",
"patient/Task.rsu"
]
}
},
"iat": 1770664341
}
eyJhbGciOiJFUzI1NiIsImtpZCI6Im52T0dSQ3NUejJRSVFMc2JsMFpRX3V4MHRmeWg1aWF2ZS1qdk5zQU5XdjgifQ.eyJpc3MiOiJodHRwczovL3JlZmVycmluZy1laHIub3JnIiwic3ViIjoiaHR0cHM6Ly9mb29kYmFuay5vcmcvYXBwcy9pbnRha2UiLCJhdWQiOiJodHRwczovL3JlZmVycmluZy1laHIub3JnIiwiZXhwIjoxNzcwNjY3OTQxLCJ0aWNrZXRfdHlwZSI6Imh0dHBzOi8vc21hcnRoZWFsdGhpdC5vcmcvcGVybWlzc2lvbi10aWNrZXQtdHlwZS9zb2NpYWwtY2FyZS1yZWZlcnJhbC12MSIsImNsaWVudF9iaW5kaW5nIjp7Imp3a3NfdXJpIjoiaHR0cHM6Ly9mb29kYmFuay5vcmcvandrcy5qc29uIn0sInRpY2tldF9jb250ZXh0Ijp7InN1YmplY3QiOnsicmVzb3VyY2VUeXBlIjoiUGF0aWVudCIsInJlZmVyZW5jZSI6IlBhdGllbnQvMTIzIn0sImFjdG9yIjp7InJlc291cmNlVHlwZSI6IlByYWN0aXRpb25lclJvbGUiLCJjb250YWluZWQiOlt7InJlc291cmNlVHlwZSI6IlByYWN0aXRpb25lciIsImlkIjoicDEiLCJuYW1lIjpbeyJmYW1pbHkiOiJWb2x1bnRlZXIiLCJnaXZlbiI6WyJBbGljZSJdfV0sInRlbGVjb20iOlt7InN5c3RlbSI6ImVtYWlsIiwidmFsdWUiOiJhbGljZUBmb29kYmFuay5vcmcifV19LHsicmVzb3VyY2VUeXBlIjoiT3JnYW5pemF0aW9uIiwiaWQiOiJvMSIsIm5hbWUiOiJEb3dudG93biBGb29kIEJhbmsifV0sInByYWN0aXRpb25lciI6eyJyZWZlcmVuY2UiOiIjcDEifSwib3JnYW5pemF0aW9uIjp7InJlZmVyZW5jZSI6IiNvMSJ9fSwiY29udGV4dCI6eyJ0eXBlIjp7InN5c3RlbSI6Imh0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vdjMtQWN0UmVhc29uIiwiY29kZSI6IlJFRkVSIiwiZGlzcGxheSI6IlJlZmVycmFsIn0sImZvY3VzIjp7InN5c3RlbSI6Imh0dHA6Ly9zbm9tZWQuaW5mby9zY3QiLCJjb2RlIjoiNzMzNDIzMDAzIiwiZGlzcGxheSI6IkZvb2QgaW5zZWN1cml0eSJ9fSwiY2FwYWJpbGl0eSI6eyJzY29wZXMiOlsicGF0aWVudC9TZXJ2aWNlUmVxdWVzdC5yc3UiLCJwYXRpZW50L1Rhc2sucnN1Il19fSwiaWF0IjoxNzcwNjY0MzQxfQ.8nQN_W7M7myhhdW00oajZnQnmDusD-p54gxZNjuNZtVUUnqXpY2zAh8VnySQRmCC0SFe15L5a6cbNNR5siYtKA
A Payer requests clinical documents to support a specific claim.
Patient (Reference).Organization (Payer NPI).type = CLMATTCH (Claim Attachment), focus = Appendectomy (SCT 80146002).scopes = patient/DocumentReference.rs, patient/Procedure.rs.{
"alg": "ES256",
"kid": "nvOGRCsTz2QIQLsbl0ZQ_ux0tfyh5iave-jvNsANWv8"
}
{
"iss": "https://provider.com",
"sub": "https://payer.com/apps/claims-processor",
"aud": "https://provider.com",
"exp": 1770667941,
"ticket_type": "https://smarthealthit.org/permission-ticket-type/payer-claims-adjudication-v1",
"client_binding": {
"jwks_uri": "https://payer.com/jwks.json"
},
"ticket_context": {
"subject": {
"resourceType": "Patient",
"reference": "Patient/456"
},
"actor": {
"resourceType": "Organization",
"identifier": [
{
"system": "http://hl7.org/fhir/sid/us-npi",
"value": "9876543210"
}
],
"name": "Blue Payer Inc"
},
"context": {
"type": {
"system": "http://terminology.hl7.org/CodeSystem/v3-ActReason",
"code": "CLMATTCH",
"display": "Claim Attachment"
},
"focus": {
"system": "http://snomed.info/sct",
"code": "80146002",
"display": "Appendectomy"
}
},
"capability": {
"scopes": [
"patient/DocumentReference.rs",
"patient/Procedure.rs"
]
}
},
"iat": 1770664341
}
eyJhbGciOiJFUzI1NiIsImtpZCI6Im52T0dSQ3NUejJRSVFMc2JsMFpRX3V4MHRmeWg1aWF2ZS1qdk5zQU5XdjgifQ.eyJpc3MiOiJodHRwczovL3Byb3ZpZGVyLmNvbSIsInN1YiI6Imh0dHBzOi8vcGF5ZXIuY29tL2FwcHMvY2xhaW1zLXByb2Nlc3NvciIsImF1ZCI6Imh0dHBzOi8vcHJvdmlkZXIuY29tIiwiZXhwIjoxNzcwNjY3OTQxLCJ0aWNrZXRfdHlwZSI6Imh0dHBzOi8vc21hcnRoZWFsdGhpdC5vcmcvcGVybWlzc2lvbi10aWNrZXQtdHlwZS9wYXllci1jbGFpbXMtYWRqdWRpY2F0aW9uLXYxIiwiY2xpZW50X2JpbmRpbmciOnsiandrc191cmkiOiJodHRwczovL3BheWVyLmNvbS9qd2tzLmpzb24ifSwidGlja2V0X2NvbnRleHQiOnsic3ViamVjdCI6eyJyZXNvdXJjZVR5cGUiOiJQYXRpZW50IiwicmVmZXJlbmNlIjoiUGF0aWVudC80NTYifSwiYWN0b3IiOnsicmVzb3VyY2VUeXBlIjoiT3JnYW5pemF0aW9uIiwiaWRlbnRpZmllciI6W3sic3lzdGVtIjoiaHR0cDovL2hsNy5vcmcvZmhpci9zaWQvdXMtbnBpIiwidmFsdWUiOiI5ODc2NTQzMjEwIn1dLCJuYW1lIjoiQmx1ZSBQYXllciBJbmMifSwiY29udGV4dCI6eyJ0eXBlIjp7InN5c3RlbSI6Imh0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vdjMtQWN0UmVhc29uIiwiY29kZSI6IkNMTUFUVENIIiwiZGlzcGxheSI6IkNsYWltIEF0dGFjaG1lbnQifSwiZm9jdXMiOnsic3lzdGVtIjoiaHR0cDovL3Nub21lZC5pbmZvL3NjdCIsImNvZGUiOiI4MDE0NjAwMiIsImRpc3BsYXkiOiJBcHBlbmRlY3RvbXkifX0sImNhcGFiaWxpdHkiOnsic2NvcGVzIjpbInBhdGllbnQvRG9jdW1lbnRSZWZlcmVuY2UucnMiLCJwYXRpZW50L1Byb2NlZHVyZS5ycyJdfX0sImlhdCI6MTc3MDY2NDM0MX0.0r9rL853T3j-aWf0Perrp0s7Wm9j1dsOo4Gq1zvmNH-1MySJI1WrrQPPNyrzAOqTg3UN0yeVXG7wolHcsA0cug
A patient consents to a study. The ticket proves consent exists without requiring the researcher to be a "user" at the hospital.
Patient (MRN).Organization (Research Institute ID).type = RESCH (Biomedical Research), focus = Malignant tumor of lung (SCT 363358000).scopes = patient/*.rs, periods (Start/End Date).{
"alg": "ES256",
"kid": "nvOGRCsTz2QIQLsbl0ZQ_ux0tfyh5iave-jvNsANWv8"
}
{
"iss": "https://consent-platform.org",
"sub": "https://research.org/studies/lung-cancer/app",
"aud": "https://hospital.com",
"exp": 1770667941,
"ticket_type": "https://smarthealthit.org/permission-ticket-type/research-study-v1",
"client_binding": {
"jwks_uri": "https://research.org/jwks.json"
},
"ticket_context": {
"subject": {
"resourceType": "Patient",
"identifier": [
{
"value": "MRN-123"
}
]
},
"actor": {
"resourceType": "Organization",
"name": "Oncology Research Institute",
"identifier": [
{
"value": "research-org-id"
}
]
},
"context": {
"type": {
"system": "http://terminology.hl7.org/CodeSystem/v3-ActReason",
"code": "RESCH",
"display": "Biomedical Research"
},
"focus": {
"system": "http://snomed.info/sct",
"code": "363358000",
"display": "Malignant tumor of lung"
}
},
"capability": {
"scopes": [
"patient/*.rs"
],
"periods": [
{
"start": "2020-01-01",
"end": "2025-01-01"
}
]
}
},
"iat": 1770664341
}
eyJhbGciOiJFUzI1NiIsImtpZCI6Im52T0dSQ3NUejJRSVFMc2JsMFpRX3V4MHRmeWg1aWF2ZS1qdk5zQU5XdjgifQ.eyJpc3MiOiJodHRwczovL2NvbnNlbnQtcGxhdGZvcm0ub3JnIiwic3ViIjoiaHR0cHM6Ly9yZXNlYXJjaC5vcmcvc3R1ZGllcy9sdW5nLWNhbmNlci9hcHAiLCJhdWQiOiJodHRwczovL2hvc3BpdGFsLmNvbSIsImV4cCI6MTc3MDY2Nzk0MSwidGlja2V0X3R5cGUiOiJodHRwczovL3NtYXJ0aGVhbHRoaXQub3JnL3Blcm1pc3Npb24tdGlja2V0LXR5cGUvcmVzZWFyY2gtc3R1ZHktdjEiLCJjbGllbnRfYmluZGluZyI6eyJqd2tzX3VyaSI6Imh0dHBzOi8vcmVzZWFyY2gub3JnL2p3a3MuanNvbiJ9LCJ0aWNrZXRfY29udGV4dCI6eyJzdWJqZWN0Ijp7InJlc291cmNlVHlwZSI6IlBhdGllbnQiLCJpZGVudGlmaWVyIjpbeyJ2YWx1ZSI6Ik1STi0xMjMifV19LCJhY3RvciI6eyJyZXNvdXJjZVR5cGUiOiJPcmdhbml6YXRpb24iLCJuYW1lIjoiT25jb2xvZ3kgUmVzZWFyY2ggSW5zdGl0dXRlIiwiaWRlbnRpZmllciI6W3sidmFsdWUiOiJyZXNlYXJjaC1vcmctaWQifV19LCJjb250ZXh0Ijp7InR5cGUiOnsic3lzdGVtIjoiaHR0cDovL3Rlcm1pbm9sb2d5LmhsNy5vcmcvQ29kZVN5c3RlbS92My1BY3RSZWFzb24iLCJjb2RlIjoiUkVTQ0giLCJkaXNwbGF5IjoiQmlvbWVkaWNhbCBSZXNlYXJjaCJ9LCJmb2N1cyI6eyJzeXN0ZW0iOiJodHRwOi8vc25vbWVkLmluZm8vc2N0IiwiY29kZSI6IjM2MzM1ODAwMCIsImRpc3BsYXkiOiJNYWxpZ25hbnQgdHVtb3Igb2YgbHVuZyJ9fSwiY2FwYWJpbGl0eSI6eyJzY29wZXMiOlsicGF0aWVudC8qLnJzIl0sInBlcmlvZHMiOlt7InN0YXJ0IjoiMjAyMC0wMS0wMSIsImVuZCI6IjIwMjUtMDEtMDEifV19fSwiaWF0IjoxNzcwNjY0MzQxfQ.0IS9YRm8svMGDD3DSt9WnpIiicXz_HoTssGOh8Qf0MLznYkQ2wmtiJvaNjV3fS0mvYq_qVk_by-Jb0ICWX_vdw
A Specialist (Practitioner) requests data from a Referring Provider.
Patient (Reference).Practitioner (NPI).type = REFER (Referral), focus = Atrial fibrillation (SCT 49436004).scopes = patient/*.rs.{
"alg": "ES256",
"kid": "nvOGRCsTz2QIQLsbl0ZQ_ux0tfyh5iave-jvNsANWv8"
}
{
"iss": "https://referring-ehr.org",
"sub": "https://specialist-clinic.org/apps/referral-viewer",
"aud": "https://referring-ehr.org",
"exp": 1770667941,
"ticket_type": "https://smarthealthit.org/permission-ticket-type/provider-consult-v1",
"client_binding": {
"jwks_uri": "https://specialist-clinic.org/jwks.json"
},
"ticket_context": {
"subject": {
"resourceType": "Patient",
"reference": "Patient/999"
},
"actor": {
"resourceType": "Practitioner",
"identifier": [
{
"system": "http://hl7.org/fhir/sid/us-npi",
"value": "1112223333"
}
],
"name": [
{
"family": "Heart",
"given": [
"A."
]
}
]
},
"context": {
"type": {
"system": "http://terminology.hl7.org/CodeSystem/v3-ActReason",
"code": "REFER",
"display": "Referral"
},
"focus": {
"system": "http://snomed.info/sct",
"code": "49436004",
"display": "Atrial fibrillation"
}
},
"capability": {
"scopes": [
"patient/*.rs"
]
}
},
"iat": 1770664341
}
eyJhbGciOiJFUzI1NiIsImtpZCI6Im52T0dSQ3NUejJRSVFMc2JsMFpRX3V4MHRmeWg1aWF2ZS1qdk5zQU5XdjgifQ.eyJpc3MiOiJodHRwczovL3JlZmVycmluZy1laHIub3JnIiwic3ViIjoiaHR0cHM6Ly9zcGVjaWFsaXN0LWNsaW5pYy5vcmcvYXBwcy9yZWZlcnJhbC12aWV3ZXIiLCJhdWQiOiJodHRwczovL3JlZmVycmluZy1laHIub3JnIiwiZXhwIjoxNzcwNjY3OTQxLCJ0aWNrZXRfdHlwZSI6Imh0dHBzOi8vc21hcnRoZWFsdGhpdC5vcmcvcGVybWlzc2lvbi10aWNrZXQtdHlwZS9wcm92aWRlci1jb25zdWx0LXYxIiwiY2xpZW50X2JpbmRpbmciOnsiandrc191cmkiOiJodHRwczovL3NwZWNpYWxpc3QtY2xpbmljLm9yZy9qd2tzLmpzb24ifSwidGlja2V0X2NvbnRleHQiOnsic3ViamVjdCI6eyJyZXNvdXJjZVR5cGUiOiJQYXRpZW50IiwicmVmZXJlbmNlIjoiUGF0aWVudC85OTkifSwiYWN0b3IiOnsicmVzb3VyY2VUeXBlIjoiUHJhY3RpdGlvbmVyIiwiaWRlbnRpZmllciI6W3sic3lzdGVtIjoiaHR0cDovL2hsNy5vcmcvZmhpci9zaWQvdXMtbnBpIiwidmFsdWUiOiIxMTEyMjIzMzMzIn1dLCJuYW1lIjpbeyJmYW1pbHkiOiJIZWFydCIsImdpdmVuIjpbIkEuIl19XX0sImNvbnRleHQiOnsidHlwZSI6eyJzeXN0ZW0iOiJodHRwOi8vdGVybWlub2xvZ3kuaGw3Lm9yZy9Db2RlU3lzdGVtL3YzLUFjdFJlYXNvbiIsImNvZGUiOiJSRUZFUiIsImRpc3BsYXkiOiJSZWZlcnJhbCJ9LCJmb2N1cyI6eyJzeXN0ZW0iOiJodHRwOi8vc25vbWVkLmluZm8vc2N0IiwiY29kZSI6IjQ5NDM2MDA0IiwiZGlzcGxheSI6IkF0cmlhbCBmaWJyaWxsYXRpb24ifX0sImNhcGFiaWxpdHkiOnsic2NvcGVzIjpbInBhdGllbnQvKi5ycyJdfX0sImlhdCI6MTc3MDY2NDM0MX0.rht6Plj_4Hcojgflvlt6wmhiydoGMhPeUtyGX1RanSu-GqIvDXUs_U6MPsXzqTSpGYtUdVEhiDtOoU7JB4xGug
The following TypeScript interfaces define the structure of the Permission Ticket and the Client Assertion.
export interface PermissionTicket {
iss: string; // Issuer URL (Trust Broker)
sub: string; // Issuer-defined subject (profile-specific)
aud: string; // Audience (Network/Data Holder set)
exp: number; // Expiration Timestamp
ticket_type?: string; // Required for multi-ticket profiles; optional for single-ticket profiles
client_binding: {
jwks_uri?: string; // Exactly one of jwks_uri or jwks
jwks?: { keys: any[] };
};
iat?: number; // Issued-at timestamp
jti?: string; // Unique Ticket ID
revocation?: {
url: string; // CRL URL
rid: string; // Revocation ID
};
ticket_context: {
subject: {
type?: "match" | "reference";
resourceType?: string;
id?: string;
identifier?: any[];
traits?: {
resourceType: "Patient";
name?: { family?: string; given?: string[] }[];
birthDate?: string;
identifier?: any[];
};
reference?: string;
};
actor?: {
resourceType: "PractitionerRole" | "RelatedPerson" | "Organization" | "Practitioner";
name?: any;
identifier?: any[];
telecom?: any[];
type?: any[];
relationship?: any[];
contained?: any[];
practitioner?: { reference: string };
organization?: { reference: string };
};
context?: {
type: { system?: string; code?: string; display?: string; };
focus?: { system?: string; code?: string; display?: string; };
identifier?: { system?: string; value: string; }[];
};
capability: {
scopes?: string[];
periods?: { start?: string; end?: string; }[];
locations?: { state?: string; country?: string; }[];
organizations?: { identifier?: any[]; name?: string; }[];
};
};
}
export interface ClientAssertion {
iss: string; // Client ID
sub: string; // Client ID
aud: string; // Token Endpoint URL
jti: string; // Unique Assertion ID
iat?: number; // Issued-at Timestamp
exp?: number; // Expiration Timestamp
permission_ticket_profile: string; // Primary processing selector
permission_tickets: string[];
}
alg and kid (Key ID) to facilitate key rotation.PermissionTicket. Public keys SHALL be exposed via a JWK Set URL (e.g., https://trust-broker.org/.well-known/jwks.json).ClientAssertion. Public keys SHALL be registered with the Data Holder or exposed via JWKS.PermissionTicket.client_binding binds redemption to a client key set (jwks_uri or embedded jwks). Data Holders verify that the client_assertion signing key is in that set.When ticket validation fails, the Data Holder SHALL return an OAuth 2.0 error response per RFC 6749.
| Scenario | error |
error_description |
|---|---|---|
| No tickets in assertion | invalid_request |
"No permission tickets provided" |
| Malformed ticket (not valid JWT) | invalid_grant |
"Malformed permission ticket" |
| Ticket signature invalid | invalid_grant |
"Ticket signature verification failed" |
| Issuer not trusted | invalid_grant |
"Ticket issuer not trusted: {iss}" |
| Issuer JWKS unavailable | invalid_grant |
"Unable to retrieve issuer keys" |
| Ticket expired | invalid_grant |
"Ticket expired" |
| Client key binding mismatch | invalid_grant |
"Ticket not bound to client key" |
aud mismatch |
invalid_grant |
"Ticket not valid for this server" |
| Unknown profile | invalid_grant |
"Unsupported permission ticket profile" |
| Profile/ticket type mismatch | invalid_grant |
"Ticket type not valid for profile" |
| Subject not resolvable | invalid_grant |
"Unable to resolve ticket subject" |
| Ticket revoked | invalid_grant |
"Ticket has been revoked" |
| Unsupported constraint | invalid_grant |
"Unsupported capability constraint: {field}" |
| No valid scopes after intersection | invalid_scope |
"No authorized scopes" |
This section defines requirements using RFC 2119 keywords (SHALL, SHOULD, MAY).
SHALL:
permission_tickets claim in client assertionspermission_ticket_profile claim in client assertionsclient_binding, aud, and expticket_type and validate against profile
For single-ticket profiles, allow omitted ticket_type; if present, validate against profilecapability constraints (scopes, periods, locations, organizations) or reject with invalid_grantrevocation is present, perform revocation checking before issuing a token; if revocation status cannot be determined, reject the requestSHOULD:
ticket_context.actor and ticket_context.context for audit trailMAY:
SHALL:
permission_tickets claimpermission_ticket_profileiss and sub in client assertion (the Client ID URL)SHOULD:
patient/Observation.rs)jti in client assertion for replay protectionSHALL:
{iss}/.well-known/jwks.jsoniss, sub, aud, exp, client_binding, ticket_contextticket_type; for single-ticket profiles, ticket_type is optionalclient_binding (jwks_uri or jwks)revocation is present, publish CRL at the URL specified in ticketsSHOULD:
jti for unique ticket identificationrid values that do not leak PII