Authorization

ButterflyMX uses the OAuth 2.0 protocol for authorization.

OAuth 2.0 is a framework that lets third-party applications request access to protected resources in the ButterflyMX API, such as buildings, tenants, and door release events. This guide describes the ButterflyMX OAuth implementation and how to integrate your application with it.

Redirect the User to the Authorization Page

To start the authorization process, build a URL like the one below and redirect the user to it:

https://accounts.na.sandbox.butterflymx.com/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code

For development, redirect_uri defaults to urn:ietf:wg:oauth:2.0:oob. Contact ButterflyMX if you need a custom redirect URI.

The user logs in through a web form. After they authenticate, the form returns an authorization code. Your application then exchanges this code for an access token and a refresh token.

Exchange the Authorization Code for Tokens

Send a POST request in the following format:

curl --location --request POST 'https://accounts.na.sandbox.butterflymx.com/oauth/token' \
--form 'grant_type=authorization_code' \
--form 'code=YOUR_AUTHORIZATION_CODE' \
--form 'client_id=YOUR_CLIENT_ID' \
--form 'client_secret=YOUR_CLIENT_SECRET' \
--form 'redirect_uri=urn:ietf:wg:oauth:2.0:oob'

Sample response:

{
  "access_token": "....",
  "token_type": "Bearer",
  "expires_in": 86400,
  "refresh_token": "....",
  "scope": "public",
  "created_at": 1726419574
}
  • The access token is valid for 24 hours (expires_in is in seconds). Send it in the Authorization: Bearer <access_token> header on API requests.
  • The refresh token is single-use. You use it once to get a new access token, and the response includes a new refresh token that replaces it.

Refresh the Access Token

When the access token expires or is about to expire, send a POST request like this:

curl --location --request POST 'https://accounts.na.sandbox.butterflymx.com/oauth/token' \
--form 'grant_type=refresh_token' \
--form 'client_id=YOUR_CLIENT_ID' \
--form 'client_secret=YOUR_CLIENT_SECRET' \
--form 'refresh_token=YOUR_CURRENT_REFRESH_TOKEN'

The response has the same format as the code exchange. It contains a new access_token and a new refresh_token.

⚠️

Refresh tokens are single-use and rotate on every refresh. Once you use a refresh token, it's invalidated. Any later request that uses it again will fail. Always replace your stored refresh token with the one returned in the response.

Handling Refresh Tokens Correctly

  • Save the new refresh token right away. Persist it before you use the new access token. If you lose it, the user must go through the authorization flow again.
  • Keep one refresh token per authorization. Don't share a refresh token across services, servers, or processes. If two of them refresh at the same time, one of them uses a token that has already been consumed and fails.
  • Centralize refreshing. If multiple workers need access tokens, route refreshes through a single component, or use a lock, so that only one refresh happens at a time. Other workers should read the current access token from shared storage instead of refreshing on their own.
  • Refresh before expiry, not on every request. Use created_at + expires_in to decide when to refresh, and leave a safety margin (for example, refresh a few minutes before expiry).
  • Handle refresh failures. If a refresh fails because the token is invalid, send the user through the authorization flow again. Don't retry with the same refresh token.
  • Store tokens securely. Treat refresh tokens like passwords. Keep them server-side, encrypted at rest, and out of logs.