Skip to main content

Token Endpoint

Description

[ POST ] /oauth2/v1/token

  • The OAuth token endpoint is used to obtain access tokens.
  • An access token must be provided as a bearer token with any request to an API used to read, write, or update data in athenaOne.
  • The sequence for calling the tok en endpoint is different for apps using 2-legged OAuth versus 3-legged OAuth.
  • An app using 2-legged OAuth can call the token endpoint directly to obtain an access token.
  • An app using 3-legged OAuth must first call the authorize endpoint to request and obtain consent from an end user, such as a provider or patient.
  • As a byproduct of end user authorization, the token endpoint response for 3-legged OAuth may also contain an ID token, refresh token, or launch context.
Token Authentication Using Client Secret
  • When utilizing secret-based authentication, your application is assigned a client secret linked to its client ID.
  • This client secret should be included in the basic authorization header of each request made to the token endpoint.
  • It is crucial to maintain the confidentiality of your client ID and secret to ensure security.
  • Sharing your client ID or secret is strongly discouraged, as it can compromise the integrity of your account.
  • In the event that your client ID or secret is compromised, new credentials will need to be generated and associated with your account as a security measure.

Token Generation

Make a request using basic authentication and include your client ID and client secret in the basic authorization header to request a token using secret-based authentication. Use the following parameters in your request.

curl https://api.preview.platform.athenahealth.com/oauth2/v1/token \
-X POST \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d "grant_type=client_credentials" \
-d "scope=athena/service/Athenanet.MDP.*"

Troubleshooting

The common error of POSTing the username and password is an ineffective approach and does not work for authentication. It must use basic authentication (essentially, "$key:$secret" Base64 encoded).

Token Authentication Using JWKS (JSON Web Key Sets)
  • Client-assertion JWT-based authentication utilizes a public/private keypair to authenticate the caller to the token endpoint.
  • This approach eliminates the need for a client secret in your application.
  • To implement this authentication method, you need to generate a public/private keypair (refer to the provided link for instructions on generating keypairs).
  • Your application must associate at least one public key with your application, which can be done either through a self-hosted JWKS URL or by importing your public JWKS.
  • JWT-based authentication with JWKS requires additional steps and involvement from the end-user.
  • It involves generating keypairs and signing JWT assertions to retrieve a token.
  • The advantage of using this method is increased security, as the private portion of your keypair remains in your control.
  • Note that using a self-hosted JWKS URL provides even greater control and security compared to importing your public JWKS, as it grants you ownership of your keys and facilitates key rotation.
  • JWKS also allows for zero-downtime rotation of credentials.
  • You can have multiple public keys associated with your app, typically recommended to have 1-5 keys.
  • Rotating credentials involves introducing a new keypair, transitioning your code to use the new keypair, and then deleting the old keypair.

Forming the JWT Assertion

To request a token using the client assertion JWT method, you need to sign a JWT assertion using the private portion of a keypair associated with your app. This signed assertion is then provided to the token endpoint for authentication. The assertion JWT must include the following claims:

ClaimDescriptionType
audRequird. The URL of the backend authorization resource. This varies by environment,listed below.Preview :https://athena.okta.com/oauth2/aus2hfei6ookPyyCA297/v1/token.Production:https://athena.okta.com/oauth2/aus2hff5eqFb7Wqfh297/v1/tokenString
expRequired. An expiration time for this token in seconds since the epoch.Must be less than an hour into the future. The assertion token will no longer be valid after this time expires.String
issRequired. Set to the client ID of the application for which you're requesting a token.String
subRequired. Set to the client ID of the application for which you're requesting a token.String

Constructing the Client Assertion JWT

Generate a JWT by including the required claims as indicated above. An example is provided below in javascript using the library. Similar libraries exist in most languages. A collection of libraries is listed on the jwt.io site. Take care when considering the use of a third-party package.

const njwt = require("njwt");
const fs = require("fs");
// Some packages require the key in pem format, you can use a package such as
// pem-jwk to convert.

Requesting the Token To request a token with the JWT you've generated, include the JWT along with the other parameters as demonstrated below:

Construct the client assertion JWT using a script like the above.

JWT=$(node generate-jwt.js)
# Include the JWT in a token request with the appropriate parameters for the
# environment.
Token Authentication Using PKCE
  • athenahealth's authorization server requires token authentication using PKCE for native or single-page browser apps using 3-legged OAuth that cannot securely store a client secret,following OAuth best practices and SMART App Launch v2.0.0 proposals.
  • PKCE (Proof Key for Code Exchange) enhances the OAuth 2.0 Authorization Code Flow.
  • Your app must generate a unique secret called a "code verifier" for each token request.
  • The code verifier is verified by athenahealth's authorization server.
  • It is used to create a transformed value called a "code challenge", which is included in the authorize request along with the code challenge method.
  • Both the code challenge and code challenge method need to be provided in your app's authorize request.
  • The code verifier is then sent in the token request. To implement PKCE for your app, you can refer to the following resources:
  • The official PKCE overview provided by the IETF (Internet Engineering Task Force).
  • Okta's implementation documentation, which offers details and restrictions on the code verifier, code challenge, and code challenge method parameters.

Input Parameters

IMPORTANT: Endpoint requires client authentication. Refer to samples in sections above for token authentication method applicable to your app.

InputTypeDescription
grant_type*stringFor 2-legged OAuth, the value is always client_credentials.For 3-legged OAuth, either the value is authorization_code to initially request an access token, or the value is refresh_token to obtain a new access token from a refresh token.
redirect_uristringRequired if grant_type is authorization_code (3-legged OAuth only). The value is the post-login redirect URI for your app and must match the value for redirect_uri provided to the authorize endpoint.
codestringRequired if grant_type is authorization code (3-legged OAuth only). The value is the code parameter returned by the authorize endpoint.
code_verifierstringRequired for token authentication using PKCE if grant_type is authorization_code (3-legged OAuth only) and your app cannot securely store or does not have a client secret. The value is a one-time use, unique string generated by your app, conforming to Okta’s code verifier requirements and for which the transformed value (code challenge) and transformation method (code challenge method) were provided to the authorize endpoint.
refresh_tokenstringRequired if grant_type is refresh_token. The value is the refresh token returned by the authorize endpoint.
scopestringRequired if grant_type is client_credentials (2-legged OAuth) or refresh_token (3-legged OAuth only). The value is a space-delimited, case-sensitive string of requested scopes. If grant_type is refresh_token, the requested scopes must be a subset of those provided to the authorize endpoint when the refresh token was originally generated.

Output Parameters & Token Types

The token endpoint returns a JSON object including up to 3 types of JWTs and associated information:

TokenDescription
access_tokenJWT to be used as a bearer token in subsequent API requests
token_typedescribes the access token; value is always “Bearer”
expires_inrepresents the lifetime of the access token in seconds (default is 60 minutes for 2-legged OAuth and 3-legged OAuth apps)
id_tokenJWT containing information on the authenticated end user (3-legged OAuth only)
refresh_tokenJWT used to obtain a new access token without requiring re-authentication by an end user (3-legged OAuth only; default expiration is 90 days from the most recent token request that used or generated that refresh token)

If using 2-legged OAuth, the token response has the following format:

{

"access_token": "bSQeVaRd47Tnof8GWbDZTud9ghLP",

"expires_in": "300"

}

If using 3-legged OAuth, the token response has the following format:

{"token_type":"Bearer","expires_in":300,"access_token":"N09411aa6CiXmdNnkp6l7V6lk5UH","scope":"openid fhirUser offline_access launch/patient patient/AllergyIntolerance.read patient/CarePlan.read patient/CareTeam.read patient/Condition.read patient/Device.read patient/DiagnosticReport.read patient/DocumentReference.read patient/Encounter.read patient/Goal.read patient/Immunization.read patient/Location.read patient/Medication.read patient/MedicationRequest.read patient/Observation.read patient/Organization.read patient/Patient.read patient/Practitioner.read patient/Procedure.read patient/Provenance.read","refresh_token":"uw-4cwXncULPI5skwLhdIntJAVc8WeEvPpYcSZDj6PU","id_token":"eyJraWQiOiJ1Z09JUjBWSWNtVnBUejdzeFNPNmpzVk1LQXVPY3ZSOHVnY0ZsbUxMNXFRIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiIwMHVibXVjem96bmFMcGFhVzI5NyIsInZlciI6MSwiaXNzIjoiaHR0cHM6Ly9hdGhlbmEub2t0YS5jb20vb2F1dGgyL2F1czJoZmY1ZXFGYjdXcWZoMjk3IiwiYXVkIjoiMG9hYXQxZHpkc3dFZ2JjSHkyOTciLCJpYXQiOjE2NTA1NTgxNDEsImV4cCI6MTY1MDU2MTc0MSwianRpIjoiSUQudmpRQmJ1N0U4b0tzUUtZMXg1bVNnczN2aVRISXdSeWNhclRHRTVYOFIxSSIsImFtciI6WyJwd2QiXSwiaWRwIjoiMDBvNnd6c2F2ZjdVNXpsNFMyOTYiLCJhdXRoX3RpbWUiOjE2NTA1NTgxMjIsImF0X2hhc2giOiJ0WEFFTTdKdF9zaC1rcE50d011cWlRIiwiZmhpclVzZXIiOiJodHRwczovL2FwaS5wbGF0Zm9ybS5hdGhlbmFoZWFsdGguY29tL2ZoaXIvcjQvUGF0aWVudC9hLTEyMy5FLTQ1Njc4OTAifQ.oSmOlQ41imNhulLhYUYAIXzu-nHukethXIuZNaOGrptCjKbcMzIghSo63tR_KW2ROgwgkQ_xhmrjo3NwoIt9eMSDArPb_zvM94RofP0SpcF5p0K-GedWC6HKEFFsB2rwoy9BZ5405Upp6MpY1Xd-nKxaxjXaiNjmwB2qIyt7LrhfZpbPHkYdnma88IYA7AQCIvHRcUZmQ4OK_6RTxIacsp54Rhuc2hcPpUNNKrTxgdCdfXmLhLtB_LlP2kAMKvNlC-MBsvHRrlDUvIhbjioFniY7gEkx1o7M1ezfqAQXwDwMmlbLuTO4ry48Oz4fkOHeGhb-VBoHHrkx-VMyI2K-ag","patient":"a-123.E-4567890"}

The “patient” object at the end of the sample 3-legged response is referred to as the launch context and is exclusive to token requests made as part of a SMART App Launch sequence. To learn more about the launch context, refer to the section below.

Launch Context

The token endpoint response from a SMART App Launch sequence includes the launch context, which provides additional information about the app's launch. It is important to note that the launch context is returned separately from any JWTs obtained from the token endpoint.In a Patient Standalone SMART App Launch sequence, the launch context consists of a "patient" object that contains the specified patient ID for user access.On the other hand, in a Provider EHR SMART App Launch sequence, the launch context includes details about the location within the EHR from which the app was launched, along with SMART styling information. For more comprehensive information regarding the provider launch context, please refer to the Embedded Apps reference documentation available on our Developer Portal..

Use an Access Token as a Bearer Token

To interact with API endpoints for reading, writing, or updating athenaOne data, your app must perform the following steps:

  • Parse the access token from the token API response.
  • Include the access token in the header of subsequent requests made to the API endpoints.
  • By including the access token in the request header, your app can securely access the necessary API endpoints and perform operations on athenaOne data.
  • For example:
 curl “https://api.preview.platform.athenahealth.com/v1/195900/ping” \
-H”Authorization: Bearer {access_token}”

Refresh a Token

To periodically request access tokens without requiring repeated user login and approval in apps using 3-legged OAuth, the following steps can be followed:

  • Obtain a refresh token from the authorize endpoint when the offline_access scope is requested during the user's authorization.
  • Form a new token request using the refresh token to obtain an access token.
  • Include the refresh token in the refresh_token parameter and specify "refresh_token" as the valube for the grant_type parameter in the token request.
  • Specify the previously granted scopes that your app would like to include in the new access token by using the scope parameter.
  • To determine the previously granted scopes associated with an access token, you can utilize introspection or introspection-like mechanisms.
  • By following these steps, your app can securely request new access tokens using refresh tokens, allowing for continuous access to API endpoints without requiring repeated user intervention.

Reference:

https://docs.athenahealth.com/api/guides/token-endpoint