SMART App Launch
This section provides step-by-step guides for implementing SMART authorization flows with Safire.
Available Workflows
| Workflow | Description |
|---|---|
| SMART Discovery | Fetching and using SMART configuration metadata |
| Dynamic Client Registration | Register a client at runtime using RFC 7591 to obtain a client_id |
| Public Client | Authorization flow for browser-based and mobile applications |
| Confidential Symmetric Client | Authorization flow for server-side applications with client secrets |
| Confidential Asymmetric Client | Authorization flow using private_key_jwt (RSA/EC key pair) |
| POST-Based Authorization | Sending the authorization request as a form POST (authorize-post capability) |
| Backend Services | System-to-system token requests using client_credentials grant; no user interaction |
Choosing a Workflow
Does your application require a logged-in user?
│
├── YES → App Launch flow (authorization_code grant)
│ │
│ Is your application a server-side web app
│ that can securely store credentials?
│ │
│ ├── YES → Can you use asymmetric key pairs (RSA/EC)?
│ │ │
│ │ ├── YES → Confidential Asymmetric Client
│ │ │ (private_key_jwt with signed JWT assertions)
│ │ │
│ │ └── NO → Confidential Symmetric Client
│ │ (client_secret with HTTP Basic auth)
│ │
│ └── NO → Public Client
│ (PKCE only, no client secret)
│
└── NO → Backend Services (client_credentials grant)
(JWT assertion, no redirect or PKCE)
Common Flow
All SMART authorization flows follow this general pattern. The key differences between client types are in how they authenticate during token exchange and refresh.
sequenceDiagram
participant App
participant Safire
participant FHIR as FHIR Server
App->>Safire: Client.new(config)
Note over Safire: No network call yet
App->>Safire: authorization_url()
Safire->>FHIR: GET /.well-known/smart-configuration
FHIR-->>Safire: SmartMetadata (endpoints, capabilities)
Safire-->>App: { auth_url, state, code_verifier }
App->>FHIR: Redirect user to auth_url
FHIR-->>App: Callback with ?code=...&state=...
App->>Safire: request_access_token(code:, code_verifier:)
Note over Safire: Auth method varies by client_type:<br/>public → client_id in body<br/>confidential_symmetric → Basic auth header<br/>confidential_asymmetric → JWT assertion in body
Safire->>FHIR: POST /token
FHIR-->>Safire: { access_token, refresh_token, expires_in, ... }
Safire-->>App: token response Hash
App->>Safire: refresh_token(refresh_token:)
Safire->>FHIR: POST /token (grant_type=refresh_token)
FHIR-->>Safire: { access_token, ... }
Safire-->>App: new token response Hash