Authentication and URL Locations

Authentication is done via OAuth 2.0 client credentials. Provisioned app credentials are used to authenticate and retrieve an access token from the environment-specific OAuth token endpoint. This access token is then provided on each API request as a bearer token.

Apps must use a different set of client credentials and OAuth URLs for 2-legged OAuth (service-to-service) from those used for 3-legged OAuth (end user-authenticated) when calling athenahealth APIs. The remaining sections on this page apply only to 2-legged OAuth. For 3-legged OAuth, please click here for documentation including associated OAuth URLs, sample code, and FAQs. Client credentials for 3-legged OAuth cannot be created or issued through the Developer Portal Console and are currently limited to patient-facing applications and read-only access to Certified APIs. To request 3-legged OAuth credentials for a patient-facing application, please complete our Certified API request form, checking the box indicating 3-legged OAuth, and submit your completed form to

Token Authentication

To authenticate against the token endpoint, we support both secret-based authentication as well as client assertion JWT-based authentication. Secret-based authentication is the simplest method, involving providing your client ID and secret in a basic authorization header when making a request to the token endpoint. JWT-based authentication is more involved, but also more secure. A JWT is generated and signed with a public/private keypair by the caller and presented to the token endpoint. The call is authenticated if the JWT's signature can be verified using one of the app's public keys. These methods are explained in more detail below.

IMPORTANT: Each token is valid for one hour and should be cached to avoid rate limit issues against the token endpoint. There is a 50 per minute rate limit in production and a 5 per minute rate limit in preview on new token requests. If you exceed this limit, your application will be blocked (429 response) from requesting new tokens for the remainder of the minute.

Environment URLs

Apps are provisioned against a specific environment and may only be used in that environment. The below URLs are used for all access to authentication endpoints and API resources, regardless of token authentication method.

athena Environment

Site (API path)

OAuth Endpoint



Secret-Based Authentication

When using secret-based authentication, your app will have a client secret associated with its client ID. This secret will be passed in a basic authorization header on every request to the token endpoint.

Please remember that as a security measure, you should never share your client ID or secret. If this happens, we will need to create another set of credentials associated with your account.

Token Generation

To request a token using secret-based authentication, make a request with the following parameters utilizing basic authentication to include your client ID and client secret in a basic authorization header.

curl \ 
-X POST \ 
-d "grant_type=client_credentials" \ 
-d "scope=athena/service/Athenanet.MDP.*"


There is a common error that involves POSTing the username and password. This does not work. It must use basic authentication (essentially, "$key:$secret" Base64 encoded).

Client Assertion JWT-Based Authentication

Client-assertion JWT-based authentication uses a public/private keypair to authenticate the caller to the token endpoint. Using this approach, your application will have no client secret. You must associate at least one public key with your application and can have up to five public keys associated. You can never have fewer than one key associated with your app.

JWT-based authentication is more involved for the end-user, requiring you to generate keypairs and sign JWT (JSON Web Token) assertions to retrieve a token. The benefit of using this method is that it is more secure. The private portion of your keypair is never out of your hands. This method also enables zero-downtime rotation of credentials. You can have up to five public keys associated with your app enabling you to rotate by: introducing a new keypair, transitioning your code to use this new keypair, and then deleting the old keypair once you've transitioned. Using the secret-based authentication method as soon as the secret is rotated your previous secret is invalid.

Requesting a Token

Requesting a token using the client assertion JWT-method requires that you sign a JWT assertion using the private portion of a keypair associated with your app. This assertion is then provided to the token endpoint for authentication. The assertion JWT must contain the following claims:

Required Assertion Claims





Required. The URL of the backend authorization resource. This varies by environment, listed below.



Required. 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.



Required. Set to the client ID of the application for which you're requesting a token.



Required. Set to the client ID of the application for which you're requesting a token.


Environment-Specific aud Claim URLs


aud Claim URL



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 njwt library. Similar libraries exist in most languages. A collection of libraries is listed on the 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.  

const privateKey = fs.readFileSync("private.pem");  

const clientId = "<Your Client ID>";  

const now = Math.floor(new Date().getTime() / 1000);  

const expire = new Date((now + 300) * 1000);  


// Set the environment-appropriate audience claim to the appropriate URL.  

const claims = {  

  aud: "<Environment-Appropriate URL>",  



const jwt = njwt  

  // Provide the algorithm you configured your key with.  

  .create(claims, privateKey, "RS256")  

  .setHeader("kid", "<The kid of the key used in signing>")  






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. 

curl -X POST "" \  

  -H "Accept: application/json" \  

  -H "Content-Type: application/x-www-form-urlencoded" \  

  -d "grant_type=client_credentials" \  

  -d "scope=athena/service/Athenanet.MDP.*" \  

  -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \  

  -d "client_assertion=$JWT"    

Token Endpoint Response Format

The token endpoint returns a JSON object with the following format:


  "access_token": "bSQeVaRd47Tnof8GWbDZTud9ghLP", 

  "expires_in": "300" 


Breakdown of JSON Response:

  • access_token - to be used as a bearer token in API requests
  • expires_in - represents the lifetime of the token in seconds
    Note: The token lifespan is 60 minutes, which is the same as it was on the old platform. 

The access token in the response should be included in subsequent requests to API endpoints.

 curl “” \ 
  -H”Authorization: Bearer {access_token}” 

Tracking Daily Quotas

There are response headers returned upon each request for your convenience.  The headers may represent different meanings depending on the request context.  Below is a table detailing the differences. 

Request Context 



OAuth Request 


The limit of OAuth requests the app can make within a period of one minute. 

OAuth Request 


The number of remaining counts the OAuth API can be used within the minute before being rate-limited.  This count resets at the top of every minute. 

API Request 


The limit of API requests you can make in a period of one day. 

API Request 


The number of remaining counts the normal API can be used before being capped.  This count resets at midnight GMT. 

API Request 


An identifier associated with this request. 

Best Practices

The best practice for a production deployment is to maintain the key and secret in a centralized place (a key server). The key server is responsible for calling the OAuth endpoint and getting and caching (until expiration) the access token. It should then make that token available for any callers in your environment who need to make an API call. You can store the key and secret in one place and can maintain a higher level of security there (for example, a smaller number of people able to log into that particular server).

For security reasons, we urge you not to check the key and secret into your codebase.

Secrets and JWKs are listed under Credentials tab of Apps listed in your Account Dashboard.

Typically, if you see "Developer Inactive" and a 401 response, it is because you are not passing the bearer token in the Authorization header with your call to an endpoint.

Was this information helpful? Yes | No Thank you for your feedback! What went wrong? Incomplete or incorrect information | Irrelevant Content | Others

On this Page