Authentication and OAuth
Blue Button uses OAuth 2.0 with Proof Key for Code Exchange (PKCE). Your app redirects the user to Medicare.gov, they log in and grant consent, and you get an access token. Here’s the full flow.
How it works
- Your app redirects the user to the Blue Button /authorize endpoint
- The user logs into Medicare.gov with Login.gov, CLEAR, ID.me, or their Medicare.gov account and grants your app access
- Blue Button redirects back to your app with an authorization code
- Your app exchanges that code for an access token
- You use the access token to call the API
To learn more about setting up your sandbox application, see Quickstart.
Get an authorization code
To let a user authorize your app, send them to the Blue Button API /authorize endpoint with the right parameters.
Example call:
https://sandbox.bluebutton.cms.gov/v3/o/authorize/?client_id=swBu7LWsCnIRfu530qnfPw1y5vMmER3lAM2L6rq2&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Ftestclient%2Fcallback&response_type=code&scope=openid%20profile%20patient%2FPatient.rs%20patient%2FCoverage.rs%20patient%2FExplanationOfBenefit.rs&state=8e896a59f0744a8e93bf2f1f13230be5&code_challenge=Ds-QWGn89NeT5jpmHLPA3z3oy59hOkbA03B1QS13_CY&code_challenge_method=S256Note: The authorization in the example is started by an HTTP GET operation. For SMART App Launch compliance, POST-style authorization is also supported.
Authorization parameters
| Parameter | Required | Description |
|---|---|---|
client_id | Yes | Your application’s client ID |
redirect_uri | Yes | Must match a registered callback URL for your application |
response_type | Yes | Always code |
state | Yes | Random string (16+ characters) to prevent CSRF |
scope | No | Space-separated list of scopes (URL-encoded) |
code_challenge | Yes | BASE64URL(SHA256(code_verifier)) |
code_challenge_method | Yes | Always S256 |
lang | No | en (English) or es (Spanish) for the authorization screen |
The user logs in at Medicare.gov and sees what data your app is requesting. If they click Connect, Blue Button redirects back to your redirecturi with a code and state parameter. For example:
http://localhost:8080/callback?code=TSjqiZCdJwGyytGjz2GzziPfHTJ6z2&state=YOUR_STATE_VALUEAuthorization screen language selection
The Blue Button user authorization screens are available in both English (the default) and Spanish. Language selection for these screens works as follows:
- To specify the language for the Blue Button authorization screens clearly, add the optional
langparameter to your/authorizerequest. Valid values areen(English) andes(Spanish). For example:
https://sandbox.bluebutton.cms.gov/v2/o/authorize/?lang=es- If the
langparameter is omitted or is set to a value other thanenores, the API server will next check theAccept-LanguageHTTP header in the/authorizerequest.- If the language settings in a user’s web browser list Spanish higher in the preference list than English, the browser will automatically include the correct
Accept-Languagevalue to request the Spanish-language screens.
- If the language settings in a user’s web browser list Spanish higher in the preference list than English, the browser will automatically include the correct
- If neither English nor Spanish is requested via the
langparameter orAccept-Languageheader, the API server will default to the English version of the authorization screens.
Exchange the code for a token
If the user authorizes your application, the Blue Button API redirects them back to the redirecturi you registered. It appends an authorization code and the state parameter sent by your application to the URL.
For example, if the Redirect URI is http://localhost:8080/testclient/callback, the Blue Button API will redirect with this request:
GET http://localhost:8080/testclient/callback?code=TSjqiZCdJwGyytGjz2GzziPfHTJ6z2\&state=8e896a59f0744a8e93bf2f1f13230Your application should verify that the state parameter returned in the redirect URI matches the state parameter you sent in the authorization request to prevent CSRF.
Your application can now exchange the code provided in the redirected request for an access token.
To retrieve an access token, POST to the Blue Button /token endpoint providing the code with the following parameters:
- clientid
- clientsecret
- redirecturi
- granttype: authorizationcode
- code
- Codeverifier
cURL command
curl -X POST "https://sandbox.bluebutton.cms.gov/v3/o/token/" \ -u "<client_id>:<client_secret>" \ -d "code=TSjqiZCdJwGyytGjz2GzziPfHTJ6z2&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Ftestclient%2Fcallback&code_verifier=zlGzSLRQz6HrTpd3TvEraYoVPW2cknzu4tUk6wHaPFw"Token response
{ "access_token":"oQlduHNr09GKCU506GOgp8OarrAy2q", "expires_in":16768.523842, "token_type":"Bearer", "scope":"profile patient/Patient.rspatient/ExplanationOfBenefit.rs patient/Coverage.rs", "refresh_token":"wDimPGoA8vwXP51kie71vpsy9l17HN", "access_grant_expiration":"2025-09-05 19:17:53Z"}Applications in the “1 hour” access category do not receive a refresh token in the Blue Button token response.
For applications in the “1 hour” or “13 months” access expiration groups, the response shows the user’s accessgrantexpiration date.
See which access category best fits your app.
Exchange Refresh Token for New Access Token
Access tokens expire after 1 hour. You can’t use an expired access token to access data. To access data after an access token expires, request a new access token using a refresh token. Refresh tokens are available to applications in the “13 months” and “Research” access duration categories.
You can use a refresh token at any time in your application’s workflow, including before an access token expires.
To retrieve a new refresh token, POST to the Blue Button API /token endpoint with the following parameters:
clientidclientsecretgranttype: refreshtokenrefreshtoken
cURL command
curl -X POST "https://sandbox.bluebutton.cms.gov/v3/o/token/" \ -u "<client_id>:<client_secret>" \ -d "grant_type=refresh_token&refresh_token=wDimPGoA8vwXP51kie71vpsy9l17HN"Token response
Successful with 200 status code:
{ "access_token":"VD1VaT4IfjXAMlZTS9E4RVXZlkhYG7", "expires_in": 36000, "token_type": "Bearer", "scope" : "profile patient/Patient.rs patient/Coverage.rs patient/ExplanationOfBenefit.rs", "refresh_token": "7x0VkRQlRU4fRNCQL2vh239nIyucgw", "patient": "-20140000000001", "access_grant_expiration":"2025-09-05 19:17:53Z"}Revoke a token
Developers can revoke an enrollee’s previously granted access via access token and its data access grant. This action prevents the creation of new access tokens without authorization.
To revoke an access token, POST to the Blue Button API /revoke endpoint with the following parameters:
clientidclientsecrettoken
cURL command
curl -X POST --url 'https://bluebutton.cms.gov/v2/o/revoke/'\ --header 'content-type: application/x-www-form-urlencoded'\ -u <client_id>:<client_secret>\ -d 'token=oQlduHNr09GKCU506GOgp8OarrAy2q'Response
Valid requests to the /revoke endpoint will always return a 200 response, regardless of whether the requested token exists.
Expire authenticated user for sandbox testing
For testing in our sandbox, use the /expireauthenticateduser endpoint. This will expire the authorization given by a patient user.
/expireauthenticateduser can be used to test your code for the following conditions that produce the same error responses via the API:
- When an access token expires, without needing to wait for the expiration in 1 hour
- When a patient revokes access to your application
- When access granted to a patient’s data has expired
POST to the Blue Button API /expireauthenticateduser endpoint with the following parameters:
clientidclientsecretpatient ID(patient ID “-20140000000001” is used in the cURL example below)
cURL command
curl -X POST "https://sandbox.bluebutton.cms.gov/v2/o/expire_authenticated_user/-20140000000001/" \ -u "<client_id>:<client_secret>" \ -H "Content-Length: 0"Response
Successful with 200 status code:
HTTP / 1.1 200 OKCommon error responses
| Error Code | Response | Reason |
|---|---|---|
| 404 | Data Access Grant was Not Found | Patient ID has not granted access |
| 403 | FORBIDDEN | Issues with client credentials or permissions |
Native and mobile applications
The Blue Button API supports the OAuth 2.0 Authorization Framework using the authorization code grant with a confidential client type flow. To keep Medicare enrollees’ data secure during authentication, we don’t support implicit grants or public client types.
For best practices for the type of application you’re developing, review the OAuth 2.0 for Native Apps.
Use a proxy middleware server to reduce security risks. Follow a Backend-for-Frontend (BFF) authentication pattern. In the BFF pattern, a backend server performs all authorization code and refresh token exchanges. For examples of this type of proxy middleware client/server implementation, check out our sample applications available in Node or Python.
Proof Key for Code Exchange (PKCE) extension usage
To improve the security of your application, we require that you use the Proof Key for Code Exchange (PKCE) extension.
There are several reasons to use the PKCE extension:
- Ensures that the application that started the OAuth 2.0 flow is the same one that is finishing it.
- Mitigates the impact of a compromised Authorization Code by a malicious actor.
- Follows the OAuth 2.0 Security Best Current Practice
PKCE uses a code challenge that is derived from a code-verifier.
Here’s how it works:
- Generate a random codeverifier (43-128 characters, URL-safe)
- Compute the challenge: codechallenge = BASE64URL(SHA256(codeverifier))
- Send codechallenge and codechallengemethod=S256 in the /authorize request
- Send the original codeverifier when exchanging the code for a token
Scopes
Scopes define the API endpoints your application is allowed to access. The Blue Button API uses HL7 FHIR Scopes to manage access to Medicare enrollee data. Scopes are required on the auth request. If they are not requested, then an error will be returned.
| Scope | Permission |
|---|---|
patient/Patient.rs or patient/Patient.read | Read and search my patient’s general and demographic information |
patient/Patient.s | Search my general patient and demographic information. |
patient/Patient.r | Read my general patient and demographic information. |
patient/Coverage.rs or patient/Coverage.read | Read and search my Medicare and supplemental coverage information |
patient/Coverage.s | Search my Medicare and supplemental coverage information. |
patient/Coverage.r | Read my Medicare and supplemental coverage information. |
patient/ExplanationOfBenefit.rs or patient/ExplanationOfBenefit.read | Read and search my Medicare claim information |
patient/ExplanationOfBenefit.s | Search my Medicare claim information. |
patient/ExplanationOfBenefit.r | Read my Medicare claim information. |
launch/patient | Patient launch context |
openid | Retrieve information about the current logged-in user |
profile | Access the /UserInfo endpoint (OpenID Connect) |
Testing token expiration
In the sandbox, you can force-expire a user’s access grant for testing:
curl -X POST "https://sandbox.bluebutton.cms.gov/v2/o/expire_authenticated_user/-20140000000001/" \ -u "<client_id>:<client_secret>" \ -H "Content-Length: 0"This simulates token expiration, access revocation, and grant expiration — all of which produce the same error responses.
Web applications
The Blue Button API supports the Authorization Code flow for web applications running on a server. Use the following settings when registering your application:
Settings:
Client Type: Confidential
Grant Type: Authorization code
Common errors
Reused refresh token
A refresh token can only be used one time. The following is an example of an error response when attempting to reuse a refresh token:
Response (unsuccessful with 400 status code):
{ "error": "invalid_grant"}If you receive this error, verify that your application sent the correct refresh token sent the correct value. If it’s already been used, the enrollee should be directed to re-authorize following the original authorization flow above.
Client credentials or permissions problems
If your request has any issues with client credentials or permissions, the following response will be received:
Response (unsuccessful with 401 status code):
{ "error": "invalid_client"}If you receive this message, double-check that the request looks correct. If everything looks correct, email bluebuttonapi@cms.hhs.gov, and the Blue Button API team can help troubleshoot.
Expired Data Access Grant
If your authorization for accessing user data has expired, the corresponding access token will not be refreshed. Attempts to refresh the token will result in the following error message:
Response (unsuccessful with 400 status code):
{ "status_code": 400, "error": "invalid_grant", "error_description": "The authorization for accessing user data has expired. To refresh Medicare data, the end user must re-authenticate and consent to data sharing."}To re-authorize, follow the same flow described under Get an authorization code.