Session Management API
The Session Management API allows Capture API customers to programmatically create and manage user sessions with fine-grained access control through scopes.
Overview
The Session Management API is designed for EHR and LIS systems that integrate with Tiro.health using the Capture API. It enables you to:
- Create sessions programmatically with specific scopes and FHIR context
- Control access to resources throughout the session lifetime using scope-based permissions
- Handover sessions to end-users in a browser environment
- Terminate sessions when the user logs out or the session expires
This API is particularly useful when you need to:
- Launch Tiro.health forms with pre-configured patient and encounter context
- Restrict what data users can access during a session
- Integrate Tiro.health into your application's authentication flow
- Provide seamless user experience with session continuity
Authentication Required: All Session Management API endpoints require OAuth2 authentication using client credentials. See the Authentication guide for details on obtaining and using access tokens.
Session Lifecycle
A typical session follows this lifecycle:
- Session Creation: Your backend calls
POST /session, optionally including scopes and FHIR context (Patient, Encounter) - Browser Handover: The end-user's browser submits the session token to
POST /session/$handovervia form POST. The session will be activated, a secure cookie is set, and the user is redirected to Tiro.health - Active Session: The user operates within Tiro.health with access controlled by the session's scopes
- Session Termination: The session is deleted via
DELETE /session(equivalent to logout) or expires automatically
Create a Session
Creates a new authenticated session for an end-user. This endpoint can optionally include FHIR context and scope restrictions.
Request Body
- Name
scope- Type
- string
- Description
Space-separated list of requested scopes (e.g.,
"patient/Patient.read patient/Observation.write"). These scopes control what data the user can access during the session.
- Name
patient- Type
- integer
- Description
FHIR server ID of the patient to associate with this session.
- Name
encounter- Type
- integer
- Description
FHIR server ID of the encounter to associate with this session.
- Name
fhirContext- Type
- array
- Description
Array of FHIR context items using external identifiers to specify Patient and Encounter resources. Use this when integrating with systems that use different identifier namespaces. Each item should include
role: "launch"to indicate the primary launch context. See FHIR Context for details.
- Name
deployment_mode- Type
- string
- Description
Either
"embedded"or"standalone". Defaults to"embedded".
- Name
smart_web_messaging_handle- Type
- string
- Description
Optional handle for SMART Web Messaging correlation.
- Name
smart_web_messaging_origin- Type
- string
- Description
Optional origin for SMART Web Messaging target.
Create Session Request
curl -X POST https://reports.tiro.health/session \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"scope": "patient/Patient.read patient/Observation.write",
"patient": 123,
"deployment_mode": "embedded"
}'
Session Handover
The handover endpoint completes the session activation flow by consuming a one-time session token and setting the authentication cookie in the end-user's browser. This is typically called automatically when the user is redirected from your system to Tiro.health.
Form Parameters
- Name
token- Type
- string
- Description
The session token received from the session creation step. This token is single-use and expires after 5 minutes.
- Name
next- Type
- string
- Description
The URL to redirect the user to after successful session activation (typically the Tiro.health application URL).
Session Handover
<form action="https://reports.tiro.health/session/$handover"
method="POST">
<input type="hidden" name="token" value="<session_token>" />
<input type="hidden" name="next"
value="https://app.tiro.health/reports/edit?response=QuestionnaireResponse/example" />
<button type="submit">Continue to Tiro.health</button>
</form>
Response (303 See Other)
// Redirects to the 'next' URL with session cookie set
Location: https://app.tiro.health/reports/edit?response=QuestionnaireResponse/example
Set-Cookie: auth_session=<session_id>; HttpOnly; Secure; SameSite=Strict
Get Session Information
Retrieves information about the current authenticated session. This endpoint requires a valid session cookie.
Response Fields
- Name
id- Type
- integer
- Description
Unique identifier for the session.
- Name
user- Type
- object
- Description
User information including practitioner details.
- Name
data_tenant- Type
- object
- Description
Data tenant associated with this session.
- Name
active- Type
- boolean
- Description
Whether the session is currently active.
- Name
expired_timestamp- Type
- datetime
- Description
When the session expires.
- Name
created_timestamp- Type
- datetime
- Description
When the session was created.
- Name
last_modified_timestamp- Type
- datetime
- Description
When the session was last modified.
- Name
deployment_mode- Type
- string
- Description
Either
"embedded"or"standalone".
- Name
fhir_server- Type
- object
- Description
FHIR server address and granted scopes for this session.
Get Session Request
curl https://reports.tiro.health/session \
-H "Cookie: auth_session=<session_id>"
Response (200 OK)
{
"id": 12345,
"user": {
"id": 67890,
"email": "doctor@hospital.org",
"name": "Dr. Smith"
},
"data_tenant": {
"id": 1,
"name": "Hospital Name"
},
"active": true,
"expired_timestamp": "2025-11-20T18:00:00Z",
"created_timestamp": "2025-11-20T10:00:00Z",
"last_modified_timestamp": "2025-11-20T10:00:00Z",
"deployment_mode": "embedded",
"fhir_server": {
"address": "https://fhir.hospital.org/R4",
"scope": ["patient/Patient.read", "patient/Observation.write"]
}
}
Delete a Session
Terminates the current session, marking it as inactive and removing the authentication cookie. This is equivalent to logging the user out.
After deletion, the session can no longer be used and any subsequent requests with the session cookie will be rejected.
Delete Session Request
curl -X DELETE https://reports.tiro.health/session \
-H "Cookie: auth_session=<session_id>"
Response (204 No Content)
// Empty response body
Scope-based Access Control
Scopes define what actions and resources a user can access during their session. When you create a session with specific scopes, those restrictions are enforced throughout the entire session lifetime.
Scope Format
Scopes follow the FHIR SMART on FHIR format: <context>/<resourceType>.<action>
Supported formats:
patient/<resourceType>.<action>- Patient-scoped access to specific resource typessystem/<resourceType>.<action>- System-wide access to specific resource types
Examples:
patient/Patient.read- Read access to patient resources in the patient's compartmentpatient/Observation.write- Write access to observations in the patient's compartmentpatient/Encounter.read- Read access to encounters in the patient's compartmentsystem/Patient.read- System-wide read access to all patient resourcespatient/Patient.read patient/Observation.write- Multiple scopes can be combined
How Scopes Work
When a session is created with scopes:
- The scopes are stored with the session
- All FHIR API requests during the session are checked against these scopes
- Requests for resources or actions not covered by the scopes are denied
- Scopes remain active until the session is deleted or expires
Example: Restricted Session
# Create a read-only session for patient data
curl -X POST https://reports.tiro.health/session \
-H "Content-Type: application/json" \
-d '{
"scope": "patient/Patient.read patient/Encounter.read patient/Observation.read",
"patient": 123
}'
In this session, the user can read patient, encounter, and observation data but cannot modify anything. Any attempt to create or update resources will be denied.
FHIR Context
Sessions can include FHIR context to associate them with specific patients and encounters. There are two ways to specify context:
Using Direct IDs
When you have the internal FHIR server IDs, use the direct patient and encounter parameters:
{
"patient": 123,
"encounter": 456
}
This is the simplest approach when your system already uses Tiro.health's FHIR server IDs.
Using External Identifiers with fhirContext
When integrating with external systems that use their own identifier namespaces, use the fhirContext array following the SMART on FHIR launch context specification:
{
"fhirContext": [
{
"identifier": {
"system": "http://hospital.org/patient-ids",
"value": "P-12345"
},
"type": "Patient",
"role": "launch"
},
{
"identifier": {
"system": "http://hospital.org/encounter-ids",
"value": "E-67890"
},
"type": "Encounter",
"role": "launch"
}
]
}
Key features:
identifier: Specifies the external system identifier (system + value)type: Resource type (Patient or Encounter)role: "launch": Indicates this is the primary launch context for the session
Identifier Resolution
When using external identifiers, Tiro.health will:
- Look up existing resources with matching identifiers
- Create new resources if no match is found
- Associate the session with the resolved or created resources
This enables seamless cross-system integration without requiring ID mapping or pre-registration of resources.
Security Considerations
Token Expiration
- Session tokens expire after 5 minutes and are single-use only
- Active sessions have configurable expiration times
- Expired tokens cannot be used for handover and will return a 401 error
Token Security
- Session tokens should be treated as sensitive credentials
- Tokens are deleted immediately after successful handover (one-time use)
- Always use HTTPS when transmitting tokens
- Never log or store session tokens
Cookie Security
Session cookies are configured with security best practices:
HttpOnly- Cannot be accessed via JavaScriptSecure- Only transmitted over HTTPSSameSite=Strict- Protection against CSRF attacks- Scoped to
tiro.healthdomain
Best Practices
- Minimize scope - Only grant the minimum permissions needed
- Short-lived tokens - Use the default 5-minute token expiration
- Secure token transmission - Pass tokens via secure form POST, not URL parameters
- Immediate handover - Complete the handover flow as quickly as possible
- Explicit logout - Always delete sessions when users log out
- Monitor sessions - Track active sessions and their expiration times