Authentication and authorization

Gusto Embedded supports two types of tokens used throughout development:

  • system-level
  • company-level

System access tokens allow you to carry out application-level actions such as:

Company access tokens allow you to carry out company-level actions, such as:

Each partner-managed company has a single access token that cannot be used to access other companies.

System access tokens

Starting with version v2024-04-01, partner API tokens are deprecated in favor of system access tokens. These tokens improve security and allow you to:

  • Manage multiple applications per organization
  • Perform system-level actions like creating partner-managed companies and subscribing to webhooks

πŸ“˜

The token will expire after two hours. Unlike company access tokens, you can request additional system tokens anytime, even if a previous one is still active. Because of this, you don’t need to store the token unless you prefer to reuse it.

To get a system access token, send a POST request to the /oauth/token endpoint with grant_type set to system_access.

curl --location --request POST 'https://api.gusto-demo.com/oauth/token' \
--header 'Content-Type: application/json' \
--data-raw '{
  "client_id": "{{client_id}}",
  "client_secret": "{{client_secret}}",
  "grant_type": "system_access"
}'

Here’s what the response looks like:

{
  "access_token": "PF9RH-QVnURJAY9-CHX0CC71HOPq7rClhJTdLdZOLt0",
  "token_type": "Bearer",
  "created_at": 1728518070,
  "expires_in": 7200
}

To use the token, add it as a bearer token in the Authorization header:

Content-Type: application/json

Authorization: Bearer PF9RH-QVnURJAY9-CHX0CC71HOPq7rClhJTdLdZOLt0

Company access tokens

To call the API on behalf of a company, you need a company-level access token. You can get one by creating a partner-managed company or going through the in-app authorization code flow when migrating to embedded payroll.

When you create a partner-managed company, you'll receive:

  • Access_token
  • Refresh_token
  • expires_in (how many seconds before the token expires)
  • company_uuid
{
  "access_token": "JKrGqRyrYfY1PB0YhsuRkbrrWBJ5iSUODDNA28D3yMc",
  "refresh_token": "T0jHy4Oc3FWi7hDPEMPdpbGiLpB0rWeb1ZJOJVB36oU",
  "company_uuid": "d525dd21-ba6e-482c-be15-c2c7237f1364",
  "expires_in": 7200
}

πŸ“˜

Tokens use URL-safe base64 encoding.

Refreshing access tokens

Access tokens expire after two hours. If expired, API calls will return a 401 Unauthorized error.

To refresh a token, send a POST request to the /oauth/token endpoint with:

  • client_id and client_secret from your application
  • refresh_token
  • grant_type set to refresh_token
curl --location --request POST 'https://api.gusto-demo.com/oauth/token' \
--header 'Content-Type: application/json' \
--data-raw '{
  "client_id": "{{client_id}}",
  "client_secret": "{{client_secret}}",
  "refresh_token": "T0jHy4Oc3FWi7hDPEMPdpbGiLpB0rWeb1ZJOJVB36oU",
  "grant_type": "refresh_token"
}'

You’ll receive a new access and refresh token:

{
  "access_token": "737HdeXfIqgx-NfaUFRuhV7JDe6ns6ptanJSMuQzjlc",
  "token_type": "bearer",
  "expires_in": 7200,
  "refresh_token": "iEjL96L9Pndwmi-xVX3Q-xbrvvhnjHYGX87sopgGJ8E"
}

When you use the new access token in a Gusto API call, your previous refresh token will be revoked.

Token management tips

Access and refresh token pairs are tied to a resource, typically a company. Here’s an example structure for storing Gusto tokens:

ER

  • company_uuid: the Gusto company ID. You might link this to your own companies table.
  • access_token_expiration: based on the expires_in value. Since the default is 7200 seconds (2 hours), set your expiration check slightly earlier, for example, "expires_in - 60."

To prevent token refresh race conditions, lock the row when refreshing tokens. Here’s one way to handle refresh logic:

  1. Confirm the access token needs refreshing by checking if access_token_expiration is in the past or if a 401 error was returned
  2. Lock the row for the company_uuid
  3. Refresh the token
  4. Update the access and refresh tokens and reset the expiration timestamp
  5. Unlock the row
  6. Use the new access token
  7. Make sure all processes use the most recent token