Fork me on GitHub

Blue Button REST API

OAuth2 API for RESTful access to patient data

Warning: This specification was developed in 2013 and is not being actively maintained. It has not been updated with changes in its dependencies (FHIR and OAuth 2.0 Dynamic Client Registration). It should be used for historical/informational purposes only. Ongoing work that carries on the ideas from this specification is happening elsewhere in the ecosystem (e.g. SMART Health IT, Argonaut Project, and OpenID HEART Workgroup.
Note: This page documents specifications applicable to both BB+ Push (Direct email transport) and BB+ Pull (HTTP RESTful transport) protocols. It is the goal of this proposal to re-use Common components for Push and Pull apps. In this way, a system implementing both would be able to re-use the same code and patterns for common activities such as end-user authorization, dynamic client registration, and service discovery.

Before an app connects to a BlueButton+ provider, it registers with that provider as an OAuth2 Client. The registration process informs the provider what the app is called, where to find it, what permissions it might ask patients for, and how to display an authorization screen to patients.

BB+ apps register with providers using OAuth2 Dynamic Client Registration. This guide walks through the process of registering a client using open registration, as well as an example of using trusted registration which leverages BB+ Registries.

Client Types

BlueButton+ allows for several different types of clients and use cases that are differentiated along two axes: whether or not a client can reasonably guard its client_secret at runtime, and whether or not it can guard its registration_jwt at runtime (if it has one). The OAuth 2 specification defines the former class distinction as "confidential" and "public" clients, but there is not existing terminology for the latter classification. This combination leads us to a matrix of six possible application styles:

Can guard client_secret Can NOT guard client_secret
Can guard registration_jwt Trusted Confidential App Trusted Public App
Can NOT guard registration_jwt Semi-Trusted Confidential App Semi-Trusted Public App
No registration_jwt Experimental Confidential App Experimental Public App

When deciding whether and how to register with a Registry Service, a client application developer MUST determine which of the above categories are appropriate for their application. Application developers must take care to select the appropriate category for their application based on its runtime capabilites as well as policies around the data. A Registry should help enable these distinctions by explicitly asking application develoeprs about the capabilities of their applications in order to determine which policies to apply.

Trusted Confidential Application

Examples:
  • Web application where all API interactions between client and provider happen in the back channel ("server-side, away from the end-user"). This is the recommended mode for web-server based applications.
  • Native applications that can be issued a per-instance registration_jwt (using mechanisms outside the scope of this specification)
Policies:
  • Uses trusted registration
  • This is the setup with the highest assurance. Therefore authorization server can present the user with its least-scary authorization screen.
  • If the registration_jwt or client_secret are exposed, it should be considered a major security breach and system-wide invalidation of the application's instances (and re-provisioning of its registration_jwt) are reasonable and expected countermeasures.

Trusted Public Application

Examples:
  • Split server-side/in-browser application that handles dynamic registration in the back-end (server-side) but performs authorization in the browser (likely using implicit flow)
Policies:
  • Uses trusted registration
  • An application MUST pre-register its redirect_uris at the Registry Service and the authorization server MUST enforce them.
  • On the authorization page, the authorization server should disclose the name and URI of the application for users to confirm that it matches what they think they're using
  • If the registration_jwt is exposed, it should be considered a major security breach and system-wide invalidation of the application's instances (and re-provisioning of its registration_jwt) are reasonable and expected countermeasures.

Semi-Trusted Confidential Application

Examples:
  • Self-sufficient native applications that register themselves separately per installation instance based on their pre-registered parameters.
Policies:
  • Uses trusted registration
  • The registration_jwt is packaged in with the application and is therefore available to all end-users. This means that any holder of this JWT could try to register with this application's parameters and it must not be trusted for access without a user's explicit consent.
  • Authorizations servers MUST present users with the name and URI of the application that is being authorized and appropriately caution users.
  • An application MUST pre-register its redirect_uris at the Registry Service and the authorization server MUST enforce them.
  • An application SHOULD pre-register as many parameters as possible at the Registry Service and the authorization server MUST enforce them.

Semi-Trusted Public Application

Examples:
  • In-browser javascript applications that handle dynamic registration and authorization (using the implicit flow) on their own
Policies:
  • Uses trusted registration
  • The registration_jwt is packaged in with the application and is therefore available to all end-users. This means that any holder of this JWT could try to register with this application's parameters and it must not be trusted for access without a user's explicit consent.
  • Authorizations servers MUST present users with the name and URI of the application that is being authorized and appropriately caution users.
  • An application SHOULD pre-register as many parameters as possible at the Registry Service and the authorization server MUST enforce them.
  • This is likely to be a rare case in BB+.

Experimental Confidential Application

Examples:
  • Weekend project / prototype of a web or native client to be used by app developers, their friends, and family
Policies:
  • Uses open registration
  • Authorization page MUST display a warning to users that the identity of the application is unverified and MUST state that users should proceed only if they trust the app's presented redirect_uri
  • An authorization server MAY display statistics such as how many other users have authorized this application in order to help the user make their decision.

Experimental Public Application

Examples:
  • Weekend project / prototype of an in-browser or native client to be used by app developers, their friends, and family
Policies:
  • Uses open registration
  • Authorization page MUST display a warning to users that the identity of the application is unverified and MUST state that users should proceed only if they trust the app's presented redirect_uri
  • An authorization server MAY display statistics such as how many other users have authorized this application in order to help the user make their decision.

Open Registration

BlueButton+ providers must offer an open registration option. To register, an app issues an https POST to the registration endpoint, supplying registration parameters as a JSON object.
Note: Open registration is appropriate for new and experimental apps, but patient-facing authorization screens should display a warning indicating that an app's identity has not been verified. To provide a higher level of assurance, apps can perform a Trusted Registration (described below).
Title: BlueButton+ Open Registration Process
participant App
participant Provider

App->Provider: Registration Request (no JWT)
Provider->App: client_id + secret + registration token
            

Registration Parameters

Parameter Type Description
client_name string Human-readable name of the Client to be presented to the user.
client_uri string URL of the homepage of the Client.
logo_uri string URL that references a logo for the Client. If present, the server SHOULD display this image to the end user during approval
tos_uri string URL that points to a human-readable Terms of Service for the Client. The Authorization Server SHOULD display this URL to the End-User if it is given.
redirect_uris array Array of redirect URIs for use in the Authorization Code and Implicit grant types. An Authorization Server SHOULD require registration of valid redirect URIs for all clients that use these grant types in order to protect against token and credential theft attacks.
response_types array Array of the OAuth 2.0 response types that the Client may use.
  • public clients: "token" or "code"
  • confidential clients: "code"
token_endpoint_auth_method string The requested authentication type for the Token Endpoint.
  • public clients: "none"
  • confidential clients: "client_secret_basic"
grant_types array Array of OAuth 2.0 grant types that the Client may use.
  • public clients: ["implicit"] or ["authorization_code"]
  • confidential clients: ["authorization_code"]
scope string Space separated list of scope values (as described in OAuth 2.0 Section 3.3 [RFC6749]) that the client is declaring that it may use when requesting access tokens. A valid BB+ scope must include one or both of: search and summary
contacts array Array of email addresses for people responsible for this Client. The Authorization Server MAY make these addresses available to end users for support requests for the Client. An Authorization Server MAY use these email addresses as identifiers for an administrative page for this client.

Example Registration for a Public Client

POST /register HTTP/1.1
Content-Type: application/json
Accept: application/json
Host: bbplus-provider.org

{
  "client_name": "Blood Pressure Grapher",
  "client_uri": "https://bpgrapher.org",
  "logo_uri": "http://bpgrapher.org/images/logo.png",
  "contacts": [
    "plot-master@bpgrapher.org"
  ],
  "tos_uri": "https://bpgrapher.org/tos",
  "redirect_uris": [
    "https://bpgrapher.org/after-auth"
  ],
  "response_types": ["token"],
  "grant_types": ["implicit"],
  "token_endpoint_auth_method": "none",
  "scope":  "summary"
} 

Example Registration for a Confidential Client

POST /register HTTP/1.1
Content-Type: application/json
Accept: application/json
Host: bbplus-provider.org

{
  "client_name": "Blood Pressure Grapher",
  "client_uri": "https://bpgrapher.org",
  "logo_uri": "http://bpgrapher.org/images/logo.png",
  "contacts": [
    "plot-master@bpgrapher.org"
  ],
  "tos_uri": "https://bpgrapher.org/tos",
  "redirect_uris": [
    "https://bpgrapher.org/after-auth"
  ],
  "response_types": ["code"],
  "grant_types": ["authorization_code"],
  "token_endpoint_auth_method": "client_secret_basic",
  "scope":  "summary"
} 

The client will receive a unique client_id for that service provider, a client_secret that it can use to authorize at the token endpoint, as well as a registration_access_token that it can use to maintain its registration at the registration endpoint, as described in OAuth Dynamic Client Registration.

Trusted Registration

In addition to open registration, BlueButton+ providers support a Trusted Registration option. When performing a Trusted Registration, apps follow the protocol described above, with the addition of a bearer token from a BB+ Registry that the provder trusts. This trusted bearer token is a JSON Web Token signed with JSON Web Signature and is verifiable by the service provider.

Background: Client Classes and Client Instances

BB+ expects that most apps will connect to multiple BB+ providers, and many apps will run directly from multiple end-user devices. This specification balances a desire for fine-grained app registration (e.g. auditing each device's access history independently) with a need for coarser-grained permissions (e.g. disabling a rogue app across all providers, or all devices). We achieve this balance by enabling two points of control: Client Classes and Client Instances.

As an example to illustrate this distinction, let's consider an iOS-based Blood Pressure Grapher. This app is considered a "Client Class" because it's associated with a single author, homepage, logo, Terms of Service agreement, etc. As we'll describe below, this class has instances for each BB+ Provider the Blood Pressure Grapher registers with, and possibly for each device it runs on.

Client Instances per-Provider In the OAuth sense, the BP Grapher app has a separate "instance" for each (app, provider) pair it participates in. For example, it will likely use a distinct client_id to communicate with each BB+ provider. (Since client_id is assigned by each provider as part of the normal OAuth Dynamic Registration process, apps generally will have have distinct identifiers for each provider.) Still, since these instances all represent "the same app", they belong to the same Client Class.

Client Instances per-Device Similarly, if the Blood Pressure Grapher is installed on multiple iOS devices, it will be assigned a separate client_id for each (app-on-device, provider) pair it participates in. (Since client_id is assigned by each provider as part of the normal OAuth Dynamic Registration process, apps MUST be assigned distinct identifiers per-device by each provider.) Again, since these instances all represent "the same app," they belong to the same Client Class.

Instance- and Class-level Controls In this way, BB+ Providers MUST assign each instance of a Client Class a different client_id, as stated in OAuth 2 Dynamic Registration section 5.1. Apps MUST simply use the identifiers assigned. No matter which instance identifiers are assigned, BB+ Providers maintain the ability to make decisions at the Class level, so if the Blood Pressure Grapher loses trust, all of its instances can be disabled in one fell swoop.

Process overview:

Title: BlueButton+ Trusted Registration Process
participant App
participant Provider 
participant "BB+ Registry"

note over App,"BB+ Registry": Manual pre-registration
App-->BB+ Registry: Register for membership
BB+ Registry-->BB+ Registry: Verify app claims
BB+ Registry-->BB+ Registry: Store app claims,\nmake available for discovery
BB+ Registry-->App: Signed Registration JWT
note over App: Time passes... time to register
App->BB+ Registry: Lookup provider
BB+ Registry->App: Provider information
App->Provider: Registration Request + JWT
Provider->Provider: Validate issuer
Provider->BB+ Registry: Get Registry discovery information
BB+ Registry->Provider: Registry discovery information
Provider->BB+ Registry: Lookup signing key
BB+ Registry->Provider: JWK Set
Provider->Provider: Validate signature
Provider->BB+ Registry: Lookup app claims
BB+ Registry->Provider: Pre-registered app claims
Provider->Provider: Verify reg matches claims
Provider->App: client_id, secret, registration token
  1. Client Class is manually pre-registered with a BB+ Registry.
    • BB+ Registry collects any fixed app registration parameters including, at a minimum, client_name and client_uri
    • BB+ Registry verifies these parameters (according to registry-specific policy)
    • BB+ Registry makes these parameters discoverable via BB+ App Discovery
    • BB+ Registry supplies the Client Class with a pre-registration token (signed JWT) for subsequent dynamic registration operations
  2. Client Instance presents the pre-registration token (using an Authorization header or any valid mechanism from RFC6750) to the registration endpoint of the service provider (which is discoverable via the BB+ Provider Discovery.
  3. Service provider validates the pre-registration token by checking the signature against the public key of the BB+ Registry indicated by the iss field of the token (and/or doing token introspection from the iss).
  4. Service provider does application discovery based on the iss and sub fields of the token to find the apps.json entry for this application
  5. Service provider compares any dynamically registered client metadata fields to any fixed value fields discovered in apps.json
  6. Client Instance receives a client_id and client_secret as well as a registration_access_token
  7. Client Instance requests user authorization and tokens
  8. Client Instance accesses protected services at service provider

Pre-registration

First, the Client class is manually pre-registered with a BB+ Registry. This process may fix any of the client parameters listed above, such as the client_name and redirect_uris. At a minimum, client_name and client_uri must be fixed at pre-registration time. All classes of a client will share any fixed parameters.

The pre-registered client class will receive:

  • a "subject" identifier unique within the scope of the BB+ Registry. This "subject" identifer should be the same as the app's homepage (client_uri).
  • a signed registration token with the following properties:
    • iss: issuer is the URL of the BB+ Registry
    • sub: subject is an identifier from the BB+ Registry (as described above)
    • iat: timestamp of when this pre-registration information was last updated (and this token was issued)
    • exp: OPTIONAL timestamp of when this pre-registration token is no longer valid
    • kid: identifier for which key was used to sign this token at the BB+ Registray
    • these claims are combined in a JWT asymmetrically signed by the BB+ Registry.

Registration

The registration JWT from the previous step is used by instances of the client during the initial call to the registration endpoint for each service provider. The service provider now needs to validate the registration JWT, compare the client's pre-registered attributes to the ones requested dynamically, and proceed with the registration.

For example, a client may send:

POST /register HTTP/1.1
Content-Type: application/json
Accept: application/json
Authorization: Bearer ey...{JWT token omitted for brevity}...q48d
Host: bbplus-provider.org

{
  "client_name": "Blood Pressure Grapher",
  "contacts": [
    "plot-master@bpgrapher.org"
  ],
  "tos_uri": "https://bpgrapher.org/tos",
  "response_types": ["code"],
  "grant_types": ["authorization_code"],
  "token_endpoint_auth_method": "client_secret_basic",
  "scope":  "summary"
} 

Validating the JWT

All service providers within a BB+ Registry must be able to validate the signature and validity of any registration tokens. First, the provdier must parse the JWT and extract its iss (issuer) field and determine if the issuer is trusted. This trust decision will generally be a configuration option on the provider, which will have a list of Registry Services that it trusts (identified by their issuer URLs).

If the iss is from a trusted source, the provider then does discovery against the registry and finds the jwks_uri of the registry. The provider downloads the key set from this URL (using an HTTPS GET request) and extracts the key with the kid that is named in the JWT. Using that key, the provider can then validate the signature of the JWT as described in JSON Web Signatures.

It's recommended that BB+ Registries publish a token introspection endpoint to facilitate token validation by service providers. In addition to being able to check the validity of the signature on a JWT, an introspection endpoint can let a service provider determine if a JWT is still valid (or has been revoked).

Validating the Registration

The service provider does BB+ App Discovery based on the sub (subject) and iss (issuer) in the registration token to determine which client metadata fields have been set ahead of time by the pre-registration process. The provider MUST abide by and enforce all pre-registered client values. The Service provider will compare these pre-registered fields with any dynamically provided fields and determine the validity of the registration. It is RECOMMENDED that providers perform a direct string comparison between pre-registered values and the values provided by the client. If there is a mismatch in any field, the provider MUST either return an invalid_client_metadata error (as described in OAuth 2 Dynamic Registration) or replace the dynamically requested value with the pre-registered value.

Completing the Registration

Once the provider has determined that the client registration request is valid, it will generate and issue a unique client_id and registration_access_token, and if applicable, a unique client_secret. The provider MUST NOT re-use the same client_id, registration_access_token, or client_secret for different client instances, even if these instances are part of the same client class.

The provider MAY link together different client instances that are part of the same Client Class to facilitate logging, auditing, and emergency deprovisioning of compromised applications. The method for the provider doing this is out of scope of this specification.

Notes

Notes:
  • The application owner/developer is responsible for pre-registering with the BB+ Registry.
  • The service provider is responsible for matching dynamic registration claims with the pre-registered claims.
  • Client Instances present the token that comes from the pre-registration process as part of a normal dynamic registration with a particular service provider.
  • This technique allows service providers to link together multiple instances of a client based on the tokens used during registration. Service providers are responsible for linking thse client instances together if they so desire. A service provider MUST assign a unique client_id for each registered instance and MUST NOT re-use the same client_id for other instances in the class.
  • Clients are responsible (in all registration cases) for accepting and using the client_id issued to them by each service provider when talking to that service provider.
  • Even a web-server style client is going to need to get different client_id's from every service provider, which means that even a single installation of a client could have multiple "instances" as far as the network is concerned.

BlueButton+ Pull uses BB+ Registry Servers to enable discovery of BB+ Providers and BB+ Apps. Each BB+ Registry Server exposes a set of trusted providers and a set of trusted apps at well-known https URLs, using simple JSON-LD arrays. In the BB+ ecosystem, apps and providers must be pre-configured with a BB+ Registry Server (or Servers). All discovery endpoints are organized beneath .well-known/bb/ at the server's root.

Why JSON-LD?

JSON-LD provides a nice balance between idiomatic JSON and well-structured data representations. By combining a JSON payload with a JSON-LD context, properties can be expanded to full URIs so that data can be mixed and matched with other services. For example, the BB+ Provider element below can automatically be:

BB+ Registry Discovery

A BB+ Registry Server exposes a BB+ Registry discovery endpoint at: /.well-known/bb/registry.json

registry.json

registry.json is a single Registry element expressed as JSON-LD with a default @vocab from http://schema.org and additional properties defined in the BB+ JSON-LD Context

While any vocabulary from schema.org may be used in describing a BB+ Registry, the following fields are required:

Property Description
name Human-readable Name of the BB+ Registry
url Root URL of the BB+ Registry (to which .well-known/bb/registry.json can be appended)
jwks_uri URL of the JSON Web Key (JWK) set for this BB+ Registry. This URL MUST be protected by HTTPS or equivalent.
trust_bundle_uri URL of the BB+ Push Trust Bundle (.p7b, .p7c, or .p7m file). Only used for BB+ Registries that also act as BB+ Push Trust Bundles.
oauth2 Collection of OAuth2 endpoints
introspect RECOMMENDED OAuth2 introspection endpoint (As described in this draft)
registry.json example
Content-Type: application/json
Link: <http://jmandel.github.com/blue-button-plus-pull/context-json-ld.js>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"

{
  "name": "The BB+ Registry Foundation",
  "url": "http://registry.org/",
  "jwks_uri": "https://registry.org/public_key.jwks",
  "oauth2": {
    "introspect": "https://registry.org/oauth/introspect",
  }

}
            

Registered Providers

A BB+ Provider is defined as the unique combination of a data service provider (a service that serves the BB+ data API) and an authorization provider (an OAuth2 authorization server and related components). Therefore, if a given data provider allows for two different authorization services, there will be two different BB+ Providers listed at the Registry Server. Likewise, if an authorization server is used for two different data providers, it will be listed separately in two different BB+ Providers at the Registry.

A BB+ Registry Server exposes a BB+ Provider Discovery endpoint at: /.well-known/bb/providers.json

providers.json

providers.json is a JSON array of Provider elements, expressed as JSON-LD with a default @vocab from http://schema.org and additional properties defined in the BB+ JSON-LD Context

While any vocabulary from schema.org may be used in describing a provider, the following fields are required:

Property Description
name Name of the BB+ Provider organization
url Primary url of the provider organization

Each provider also exposes its endpoint URIs via the following properties:

Property Description
patient_signin URL where a patient can sign in to the Provider
oauth2 Collection of OAuth2 endpoints
registration_uri OAuth2 dynamic registration endpoint
authorize_uri OAuth2 authorization endpoint
token_uri OAuth2 token endpoint
introspect_uri OAuth2 introspection endpoint (As described in this draft)
bb_api Collection of BB+ API endpoints
summary BlueButton+ Clinical Summary endpoint
search BlueButton+ Document Search endpoint
providers.json example
Content-Type: application/json
Link: <http://blue-button.github.com/blue-button-plus-pull/context-json-ld.js>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"

[
{
  "name": "Good Health Clinic",
  "description": "Serving your health needs since 1999",
  "url": "http://goodhealthclinic.org",
  "patient_signin": "http://portal.goodhealthclinic.org",
  "location": {
    "geo": {                       
      "latitude": 42.3591,            # just making the point that we can
      "longitude": -71.0934           # use arbitrary schema.org properties
    }
  },
  "oauth2": {
    "registration_uri": "http://portal.goodhealthclinic.org/register",
    "authorize_uri": "http://portal.goodhealthclinic.org/authorize",
    "token_uri": "http://portal.goodhealthclinic.org/token"
  },
  "bb_api":{
    "summary": "http://api.goodhealthclinic.org/patient/documents/summary",
    "search": "http://api.goodhealthclinic.org/patient/documents/search"
  }
},
{
 ... (more providers here) ...
}
] 

Registered Apps

A BB+ Registry Server exposes a BB+ App Discovery endpoint at: /.well-known/bb/apps.json

apps.json

apps.json is a JSON array of App elements, expressed as JSON-LD with a default @vocab from http://schema.org and additional properties defined in the BB+ JSON-LD Context

While any vocabulary from schema.org may be used in describing a provider, the following fields are required:

Property Description
name Name of the BB+ App
url Primary url of the BB+ App
fixed_registration_parameters JSON structure containing any registration parameters that are fixed across all instances of this app. A Trusted Registration request must match on all parameters defined in the fixed_registration_parameters structure. (Note: matching requires that JSON.stringify return identical values for a given fixed registration parameter. Failure to match on any parameter results in a rejected Trusted Registration request.) This structure may include any valid client metadata reistration parameters, and the following properties MUST be locked down.
client_name client_name must be fixed across all app instances and must match the schema.org name above
client_uri client_uri must be fixed across all app instances and must match the schema.org url above
redirect_uris the set of allowable redirect_uris must be fixed across all app instances
apps.json example
Content-Type: application/json
Link: <http://blue-button.github.com/blue-button-plus-pull/context-json-ld.js>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"

[
{
  "url": "https://bpgrapher.org",
  "name": "Blood Pressure Grapher",
  "fixed_registration_parameters": {
      "client_name": "Blood Pressure Grapher",
      "client_uri": "https://bpgrapher.org",
      "logo_uri": "http://bpgrapher.org/images/logo.png",
      "contacts": [
        "plot-master@bpgrapher.org"
      ],
      "tos_uri": "https://bpgrapher.org/tos",
      "redirect_uris": [
        "https://bpgrapher.org/after-auth"
      ],
      "response_types": ["token"],
      "grant_types": ["implicit"],
      "token_endpoint_auth_method": "none",
      "scope":  "summary"
  },
},
{
 ... (more apps here) ...
}
] 

In APIs protected by OAuth 2, the scope mechanism allows the Authorization Server, Client, and Protected Resource to communicate the level of access that the client has been authorized for. These scopes are expressed at different times throughout the process:

  1. At pre-registration with a Registry, an application class may pre-register the set of scopes that its instances will be able to ask for in future steps
  2. At registration, a client instance may ask for a set of scopes to be tied to its registration
  3. At registration, an authorization server will register a client instance with a set of scopes that the client instance may ask for at the authorization endpoint
  4. At authorization, a client may ask for a set of scopes to be tied to the issued token
  5. At authorization, an end-user and authorization server will determine which scopes are associated with the issued token
  6. At token issuance, a token is associated with a set of authorized scopes expressed in the return from the token endpoint
  7. At access time, the protected resource compares the scopes associated with the token to the scopes required to access the data API in question

The scope paramter in OAuth 2 is a space-separated list of strings, and the values, syntax, and sematnics of the individual scopes are service specific. In the context of Blue Button+, scopes that are defined by the BB+ Push and Pull protocols.

Structured Scopes

In BB+, structured scopes have two parts: a root scope value and a (potentially empty) parameter value, separated by the colon ":" character. In general, the root scope value is used in the pre-registration and registration steps above (steps 1-3), and the fully-specified scope value (root:parameter) is used in the authorization, token, and access steps above (4-7). Registration for the root scope value implies permission for the client instance to ask for authorization for any fully parameterized scope based on that root. (Note that as with all OAuth 2 scopes, the permission to ask for authorization in no way guarantees or implies that authorization will be granted.)

Root Value Parameter Description
search patient record pseudo-id

In the Pull authorization protocol, search: represents access to the BB+ Search endpoint, and summary: represents access to the BB+ Summary endpoint. The scope is parameterized because in some cases the authorizing user may not be the same as the patient (for example, a parent authorizing access to her child's record). This parameter allows each party to keep track of how access tokens map to individual patients, rather than invidiual authorizing users. An empty parameter value (search: or summary:) represents the common case where a patient is authorizing access to her own record. Non-empty parameter values such as search:123 or summary:jane are used when the authorizing user is not the same person as the patient whose record is being accessed.

An authorization server need not understand the value of the parameter in order to let the user grant access, but the resource server MUST understand and enforce the value. At this time, each BB+ Pull authorization MUST be associated with exactly one patient record identifier. In other words, a given access token may only be used to access one patient's data. In step 5, the authorization server MAY prompt the user to choose a single patient record: for example, by asking the end-user to enter a code directly or choose from a list. The details of how these parameter values are defined and communicated between the protected resource, client, end-user, and authorization server are out of scope for this proposal and often out of band. (For example a pediatrician's office may provide a parent with a print-out including a short code to type in at authorization time for authorizing access to each child's record.)

summary
send-email-to DIRECT email address In the Push authorization protocol, this scope represents end-user authorization for the provider to send email to the DIRECT email address stated in the parameter value, such as send-email-to:oip8erjoiaewjoi@direct.bp-grapher.org. When used without a parameter in step 4, the authorization server MUST prompt the end user for the DIRECT email address to use. In steps 5-7, the semantics of this scope without the parameter value are undefined and out of scope for this protocol.

BlueButton+ providers allow apps to obtain patient authorization to health data using standard OAuth2 authorization flows. There are two authorization flows initially supported: Implcit Grant (appropriate only for public clients) and Authorization Code Grant (appropriate for public as well as confidential clients).

Both flows follow the same basic pattern:

  1. App redirects the browser to a BlueButton+ Provider's Authorization endpoint
  2. BB+ Provider authenticates patient and obtains authorization
  3. BB+ Provider redirects control back to App

Authorization Code Grant for public or confidential clients

1. App-to-Provider Redirection

To initiate an Authorization Code Grant authorization, the app redirects the browser to a BlueButton+ provider's Authorization endpoint with the following URL parmeters:
Parameter Description
response_type REQUIRED. Value MUST be set to code.
client_id REQUIRED. The client identifier
redirect_uri REQUIRED. Must match one of the client's pre-registered redirect URIs.
scope REQUIRED. Must include one or both of: search and summary
state RECOMMENDED. An opaque value used by the client to maintain state between the request and callback. The authorization server includes this value when redirecting the user-agent back to the client. The parameter SHOULD be used for preventing cross-site request forgery Should state be REQUIRED with a minimum level of entropy?
Example App-to-Provider Redirection (newlines added for clarity)
/authorize?
response_type=code&
client_id=bp-grapher&
redirect_uri=https%3A%2F%2Fbpgrapher.org%2Fafter-auth&
scope=search%3A+search%3A&
state=98wrghuwuogerg97

Host: bbplus-provider.org

2. Provider Authenticates Patient and Obtains Authorization

The mechanism by which providers authenticate patients and obtain authorization is out of scope for this specification

3. Provider-to-App Redirection

After a successful authorization step, the BlueButton+ provider redirects the browser to the app's redirect_uri, with the following parameters supplied in the query component.

Parameter Description
code REQUIRED. The authorization code generated by the authorization server. The authorization code MUST expire shortly after it is issued to mitigate the risk of leaks.
state REQUIRED. The exact value received from the client.
Example Provider-to-App Redirection (newlines added for clarity)
/after-oauth?
code=j0j9midoe0r9gjwro83h974t8gifb&
state=98wrghuwuogerg97

Host: bpgrapher.org

4. App exchanges authorization code for access token

After receiving an authorization code, the app issues a request to the BlueButton+ provider's Token URI to exchange the authorization code for an access token. The exchange includes the following parameters

Parameter Description
grant_type REQUIRED. Fixed value: authorization_code
code REQUIRED. Code that an app can exchange for an access token.
redirect_uri REQUIRED. The same redirect_uri used in the initial authorization request
client_id REQUIRED for public clients. May be omitted by confidential clients where the client_id is communicated via the client's authentication to the token endpoint.
Example Code-for-Token Exchange Request (Public Client)
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=j0j9midoe0r9gjwro83h974t8gifb&
redirect_uri=https%3A%2F%2Fbpgrapher.org%2Fafter-auth&
client_id=bp-grapher 
Example Code-for-Token Exchange Request (Confidential Client)
Confidential clients authenticate using HTTP Basic Auth to supply credentials. To create a Baisc Auth header, you concatenate your client_id and client_secret with a : (colon character) in between, and base64-encode the result. For example, your client_id is 123 and your client_secret is 456, then you would base64-encode the string 123:456 to yield MTIzOjQ1Ng==. This is passed to the server in an Authorization header as demonstrated below.
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic MTIzOjQ1Ng==
Content-Type: application/x-www-form-urlencoded/token?

grant_type=authorization_code&
code=j0j9midoe0r9gjwro83h974t8gifb&
redirect_uri=https%3A%2F%2Fbpgrapher.org%2Fafter-auth 

The response is a JSON object containing the following parameters

Parameter Description
access_token REQUIRED. The access token issued by the authorization server
token_type REQUIRED. Fixed value: bearer
expires_in REQUIRED. The lifetime in seconds of the access token. For example, the value "3600" denotes that the access token will expire in one hour from the time the response was generated.
scope REQUIRED. Scope of access authorized by the patient.
Example Code-for-Token Exchange Response
{
  "access_token": "i8hweunweunweofiwweoijewiwe",
  "token_type": "bearer",
  "expires_in": "3600",
  "scope": "summary:"
} 

Implicit Grant for public clients

1. App-to-Provider Redirection

To initiate an Implicit Grant authorization, the app redirects the browser to a BlueButton+ provider's Authorization endpoint with the following URL parmeters:
Parameter Description
response_type REQUIRED. Value MUST be set to token.
client_id REQUIRED. The client identifier
redirect_uri REQUIRED. Must match one of the client's pre-registered redirect URIs.
scope REQUIRED. Must include one or both of: search and summary
state RECOMMENDED. An opaque value used by the client to maintain state between the request and callback. The authorization server includes this value when redirecting the user-agent back to the client. The parameter SHOULD be used for preventing cross-site request forgery Should state be REQUIRED with a minimum level of entropy?
Example App-to-Provider Redirection (newlines added for clarity)
/authorize?
response_type=token&
client_id=bp-grapher&
redirect_uri=https%3A%2F%2Fbpgrapher.org%2Fafter-auth&
scope=search%3A+summary%3A&
state=98wrghuwuogerg97

Host: bbplus-provider.org 

2. Provider Authenticates Patient and Obtains Authorization

The mechanism by which providers authenticate patients and obtain authorization is out of scope for this specification

3. Provider-to-App Redirection

After a successful authorization step, the BlueButton+ provider redirects the browser to the app's redirect_uri, with the following parameters embedded in the URI's #fragment component.

Parameter Description
access_token REQUIRED. The access token issued by the authorization server
token_type REQUIRED. Fixed value: bearer
expires_in REQUIRED. The lifetime in seconds of the access token. For example, the value "3600" denotes that the access token will expire in one hour from the time the response was generated.
scope REQUIRED. Scope of access authorized by the patient.
state REQUIRED. The exact value received from the client.
Example Provider-to-App Redirection (newlines added for clarity)
/after-auth#
access_token=i8hweunweunweofiwweoijewiwe&
token_type=bearer&
expires_in=3600&
scope=search%3A+summary%3A&
state=98wrghuwuogerg97

Host: bbplus-provider.org 

Using the BB+ Clinical API

To access BlueButton+ Clinical API endpoints, an app:
  1. Obtains Patient Authorization via BB+ Authorization
  2. Discovers a provider's clinical API endpoints via Single-Provider Discovery
  3. Issues an authenticatd request to the endpoint, supplying its OAuth bearer token

Discovering endpoint URIs

Each BB+ Provider exposes a clinical summary endpoint and a document search endpoint. An app discovers the URLs for these endpoints at runtime by performing Single-Provider Discovery. The discovery process results in a JSON-LD object whose bb_api.* properties are used for the operations described below.

Issuing API calls

To issue an authenticated API call, an app requests the BB+ Clinical API endpoint using the appropriate HTTP method (generally GET for read-only operations), including its OAuth bearer token using an Authorization header or any valid mechanism from RFC6750.

Negotiating Content-type of the response

An app may include an Accept HTTP header with the request. Apps that are unable to set an Accept header may alternatively supply a _format query parameter. Valid content-type values are listed for each endpoint below.

Clinical Summary

Endpoint URI: bb_api.summary
The clinical summary endpoint returns the most recently available summary document. By default, BB+ Providers supply a clinical summary document in Consolidated CDA XML format. For convenience, other MIME types may be derived from a Consolidated CDA and returned to an app. Providers SHOULD support the following formats, all of which can be automatically derived from a C-CDA:
Accept header description
text/xml DEFAULT. A Consolidated CDA in XML.
text/plain A document rendered as a simple text file (as in the VA's "classic" BlueButton implementation.
text/html A document rendered as HTML (as might be obtained by applying a generic stylesheet to a C-CDA).

Using the summary endpoint

To retrieve the most recent clinical summary document, an app issues an http GET to the summary endpoint, including its bearer token using an Authorization header or any valid mechanism from RFC6750.

Example

GET /bb/record/summary HTTP/1.1
Accept: application/xml
Authorization: Bearer i8hweunweunweofiwweoijewiwe
Host: bbplus-provider.org
Endpoint URI: bb_api.search

The clinical document search endpoint allows an app to search for clinical documents that match a set of search parameters. A core set of features are described here.

The following five fields of a DocumentReference must be defined to support BB+ Document Search:

  • location to support Document Retrieval
  • format to distinguish CCDA vs. CCD 1.0 vs. CCR (see below)
  • type to describe clinical content
  • period to describe period of care

For full details, see FHIR's DocumentReference definition.

Search returns a feed of DocumentReferences

It's important to keep in mind that the document search endpoint does not return document content directly. Rather, it returns an Atom feed (or JSON equivalent) containing document descriptors in the form of FHIR's DocumentReference resources. These resources included basic document metadata as well as a URL that can be used to fetch a document's contents (see Document Retrieval below.)
Search Parameters
Query parameter Description
format Filter by information model (e.g. CCD 1.0, C-CDA, CCR).
CCR
Content expressed using the ASTM CCR Standard
CCD
Content expressed using the HL7 CCD 1.0 Standard
CCDA
Content expressed using the HL7 CCDA Standard (including CCD 1.1)
To match more than one format, separate values with ,

E.g. format=CCD,CCR
type Filter the available documents by document type. The following values are supported:
Summary
Continuity of Care Document
Consult
Consultation Note
Imaging
Diagnostic Imaging Report
Discharge
Discharge summary
HandP
History and Physical Note
Operative
Operative Note
Procedure
Procedure Note
Progress
Progress Note
Lab
Lab report
Unstructured
Unstructured document
To match more than one type, separate values with ,

E.g. type=Summary,Discharge
period:before

Filter for documents describing a period before a given time. If no time zone is specified, the server may assume local time, local time of the querying system, or some other fixed time zone.

Example: 2012-01-01T06:00-05:00 (6:00am on January 1, 2012 GMT-5)

period:after

Filter for documents describiing a period after a given time.

In addition to the search paramters described above, BB+ providers support Content-type negotiation to determine the format in which results are returned. The following formats are available:
Accept header description
text/xml DEFAULT. An Atom feed representation of DocumentReference elements.
application/json A JSON bundle of DocumentReference elements (like Atom, but in FHIR-defined JSON)

Content-type (_format) vs. format

Two distinct "format-related" parameters are used at the clinical document search endpoint, and it's important to keep them straight.
Accept header (or _format parameter)
Defines the MIME type in which search results are returned. Remember that search results are returned as a feed of DocumentReference document descriptions, and actual document content is not embedded in this feed. So this parameter simply determines whether the feed is Atom (default) or JSON.
format parameter
Search parameter to filter documents by format (e.g. CCDA vs. CCR). Note the lack of undescore.

Using the search endpoint

To search for relevant documents, an app issues an http GET to the search endpoint, including its bearer token using an Authorization header or any valid mechanism from RFC6750.

Example request

The following query obtains a JSON feed of C-CDA Operative notes and Procedure notes pertaining to episodes of care that ended prior to 2013.

Newlines and indentation added around URL parameters for clarity

GET /bb/record/DocumentReference?                      # provider-supplied endpoint
   format=CCDA&                               # limit to Consolidated CDAs
   type=Operative,Procedure&                              # limit to Operative notes *or* Procedure notes
   period:before=2013-01-01T00:00Z              # limit to care episodes that
   HTTP/1.1                                     #   (partially) occurred pre-2013
   Accept: application/json                     # return a JSON feed 
                                                #   (rather than Atom XML)
Authorization: Bearer i8hweunweunweofiwweoijewiwe
Host: bbplus-provider.org

Example response

Note: FHIR's DocumentReference document descriptor includes a lot more metadata than BB+ may need for the document search endpoint. FHIR defines many of these fields (including patientId) as required. The representation below is simplified.

In practice, to retrieve actual document contents, app developers will want to examine the entry array of the search result, and for each DocumentReference in that array, the location can be extracted and dereferenced. For more details, see Document Retrieval.

{
  "title": "Search results for resource type DocumentReference",
  "entry": [
    {
      "id": "https://bbplus-provider.org/bb/record/DocumentReference/123",
      "updated": "2013-04-22T04:15:10Z",
      "content": {
        "resourceType": "DocumentReference",
        "type": {
          "coding": [{
              "code": "Consult",
              "display": "Consultation Note"
            }]
        },
        "format": {
          "coding": [{
              "code": "CCDA",
              "display": "Consolidated CDA"
            }]
        },
        "created": "2005-12-24T09:35:00+11:00",
        "indexed": "2005-12-24T09:43:41+11:00",
        "status": "current",
        "mimeType": "text/xml",
        "location": "https://bbplus-provider.org/bb/record/Binary/9n9283829f"
      }
    }
  ]
}

Document Retrieval

Endpoint URI: this endpoint is document-specific

Retrieving an individual document

By performing a Document Search, an app obtains an Atom feed (or JSON equivalent) of DocumentReference document descriptors. To fetch actual document contents, the app issues an authenticated, HTTPS GET to dereference the document URI. This URI is available in the ./location/@value xpath for an Atom entry, or the location field of a JSON feed entry.

Example request

For the example JSON feed above, an app would fetch actual document contents via:
GET /bb/record/Binary/9n9283829f HTTP/1.1
Authorization: Bearer i8hweunweunweofiwweoijewiwe
Host: bbplus-provider.org

Patient data is stored with many providers, and manually requesting an update from each provider can be difficult for a patient. The following workflow enables BB+ Pull apps to offer patient an easy-to-use OAuth2-based mechanism for creating a BB+ Push connection. In orther words, this workflow helps user find providers and register for BB+ Push updates (Direct e-mail messaging).

In this example, assume the user is interacting with this environment:

Client
BP-Grapher
Service Provider
Good Health Clinic
Scope
send-email-to is a special, structured scope that is used to indicate the DIRECT email to send information to for this user

User Authorization Flow:

In this section, we describe how a user can authorize a service provider to send updates as new health data becomes available. To enable this process, the client must perform the following steps:

  1. Discovery as described above (provider discovery at its BB+ Registry ).
  2. Search, filter, and optionally cache discovered service providers. The user will select one or more to authorize.
  3. Dynamically register if the client doesn't already have their OAuth 2 credentials for the chosen service provider.
  4. Send the user (in a web browser) to the service provider's authorization endpoint. They have the option to authorize this provider to push their data.
  5. Verify success by requesting a token from the service provider's token endpoint to ensure the user's selection succeeded.

1. Discovery

Discovery for Push is the same process as shown above for provider discovery. A provider's information, including endpoint URIs, will be served in the following format:

{
  "name": "Good Health Clinic",
  "description": "Serving your health needs since 1999",
  "url": "http://goodhealthclinic.org",
  "location": {
    "geo": {                       
      "latitude": 42.3591,            # just making the point that we can
      "longitude": -71.0934           # use arbitrary schema.org properties
    }
  }
}

2. Search, filter, and cache

The specifics of client-side searching, filtering, caching, and selecting are out of scope for this guide. Part of the rationale for delegating this task to the client is that the implementation of these tasks may vary by platform

3. Dynamic registration

Dynamic registration for Push is the same process as shown above. This step retrieves a client_id and client_secret for this specific service provider. These values may and likely will vary across providers. If the client has already retrieved the client's ID and secret, this step can be skipped. Below is an example of the metadata sent in a request for dynamic registration and the response received.

Dynamic registration request:

{
  "url": "https://bpgrapher.org",
  "name": "Blood Pressure Grapher",
  "fixed_registration_parameters": {
    "client_name": "Blood Pressure Grapher",
    "client_uri": "https://bpgrapher.org",
    "logo_uri": "http://bpgrapher.org/images/logo.png",
    "contacts": [
      "plot-master@bpgrapher.org"
    ],
    "tos_uri": "https://bpgrapher.org/tos",
    "redirect_uris": [
      "https://bpgrapher.org/after-auth"
    ],
    "response_types": ["code"],
    "grant_types": ["authorization_code"],
    "token_endpoint_auth_method": "none",
    "scope":  "send-email-to"
  },
}

Dynamic registration response:

{
  "client_id": "bp-grapher-goodhealth",
  "client_secret": "aser98uw4ijhsdfg9r4",
  "registration_access_token": "2398askljasdf.gjo23r98adsf.asdf8923uwekljashdf7892334",
  "client_name": "Blood Pressure Grapher",
  "client_uri": "https://bpgrapher.org",
  "logo_uri": "http://bpgrapher.org/images/logo.png",
  "contacts": [
    "plot-master@bpgrapher.org"
  ],
  "tos_uri": "https://bpgrapher.org/tos",
  "redirect_uris": [
    "https://bpgrapher.org/after-auth"
  ],
  "response_types": ["code"],
  "grant_types": ["authorization_code"],
  "token_endpoint_auth_method": "none",
  "scope":  "send-email-to"
}

4. Authorization request

By this step, the client has its OAuth 2 credentials. The client will use that data to send the user to the service provider's authorization endpoint. Below is an example authorization request for the code workflow (more information is available in OAuth 2 RFC 6749 Section 4.1):

http://portal.goodhealthclinic.org/authorize?
  response_type=code&
  client_id=bp-grapher-goodhealth&
  redirect_uri=https://bpgrapher.org/after-auth&
  state=aliawejhwiluaq34hiuow&
  scope=send_email_to:oip8erjoiaewjoi@direct.bp-grapher.org

Note: The send_email_to scope construct above is asking for permission to send e-mail to the given address after the :, using a simple expression language as part of the structured scope.

At this point, the client will receive either a positive response or a failure. Hypothetically, this response reflects the ultimate results, but the next step addresses the client's ability to verify this response

Positive response: Client is redirected to:

https://bpgrapher.org/after-auth?
  state=aliawejhwiluaq34hiuow&
  code=oafea8i23n

Error response: (e.g. user clicked deny):

https://bpgrapher.org/after-auth?
  state=aliawejhwiluaq34hiuow&
  error=access_denied (Other error codes are available from 4.1.2.1)

5. Verify authorization results

To verify that the code we got is real, we request a token using the code from the token endpoint. If this returns an access token (and not an error), then we know the code we used was good and that the user actually authorized for us. Optionally, the client can also check the scope of the returned token to ensure that the requested scopes were received. Below is an example of the request for this verification:

http://portal.goodhealthclinic.org/token
  client_id=bp-grapher-goodhealth&
  client_secret=aser98uw4ijhsdfg9r4&
  redirect_uri=https://bpgrapher.org/after-auth&
  grant_type=code&
  code=oafea8i23n

The server then returns the token structure as follows:

{
  "access_token": "i8hweunweunweofiwweoijewiwe",
  "token_type": "bearer",
  "expires_in": "3600",
  "scope": "send_email_to:oip8erjoiaewjoi@direct.bp-grapher.org"
} 

Alternative Push Authorization Strategy Push

An alternative to this whole approach would be to have the Client be Good Health Clinic and the Provider be BP-Grapher, with the protected data being the email address to send things to. This is more in line with OAuth's REST-friendly model and the traditional definition of roles, but it doesn't fit as well with the PUSH methods we're trying to enable here.

Demo of Pull User Experience

For a demonstration of a BB+ Pull app (and a tutorial on how to write one), see: Growth-tastic.

Authors and contributors

Preliminary protocol specification authored by Josh Mandel, Justin Richer, Keith Boone, and Adam Goldstein for the Blue Button+ Working Group.