OAuth2

OAuth2 Authentication

OAuth2 is a standard protocol for authorization that allows users to grant third-party applications access to their resources without sharing credentials.

Overview

OAuth2 is ideal for:

  • APIs that support the OAuth2 standard
  • User-specific authentication where you need access to user data
  • Services where you want to avoid storing user credentials

Configuration

In your spec.yml:

auth:
  type: oauth2

  # Method implementations
  getOAuthConfig:
    implementationType: mapping
  makeApiClient:
    implementationType: mapping
  test:
    implementationType: javascript

  # Optional method implementations
  getTokenData:
    implementationType: javascript
  getCredentialsFromTokenResponse:
    implementationType: javascript
  refreshCredentials:
    implementationType: javascript

OAuth2 Config

The OAuth2 configuration is defined in a mapping file:

# File: auth/get-oauth-config.map.yml
clientId:
  $var: connectorParameters.clientId
clientSecret:
  $var: connectorParameters.clientSecret
authorizeUri: https://auth.example.com/oauth2/authorize
tokenUri: https://auth.example.com/oauth2/token
scopes:
  - read
  - write
clientAuthLocation: body  # or 'headers'
noRefreshToken: false
skipPkce: false
extra:
  prompt: consent
  access_type: offline

Config Parameters

ParameterDescription
clientIdThe OAuth2 client ID (usually from connector parameters)
clientSecretThe OAuth2 client secret
authorizeUriThe endpoint where users are redirected to authenticate
tokenUriThe endpoint where access tokens are obtained
scopesList of OAuth scopes to request
clientAuthLocationWhere to send client credentials (headers, body, or both if not specified)
noRefreshTokenSet to true if the API doesn't support refresh tokens
skipPkceSet to true if the API doesn't support PKCE
extraAdditional parameters to add to the authorize URI

OAuth2 Flow Implementation

Standard OAuth2 Flow

The standard OAuth2 flow works like this:

  1. User initiates authentication
  2. Integration.app redirects user to the authorizeUri with appropriate parameters
  3. User authenticates with the service and grants permissions
  4. Service redirects back to Integration.app with an authorization code
  5. Integration.app exchanges the code for access and refresh tokens
  6. The tokens are stored as connection credentials
  7. Integration.app uses the access token for API requests

Custom Token Request

If you need to customize the token exchange process, you can implement a custom getTokenData method:

// File: auth/get-token-data.js
exports.getTokenData = async function({
  connectorParameters,
  connectionParameters,
  codeVerifier,
  queryParameters,
  redirectUri
}) {
  // Custom implementation of token retrieval
  const response = await fetch(connectorParameters.tokenUri, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code: queryParameters.code,
      redirect_uri: redirectUri,
      client_id: connectorParameters.clientId,
      client_secret: connectorParameters.clientSecret,
      code_verifier: codeVerifier
      // Add any custom parameters here
    })
  });

  return await response.json();
};

Custom Credentials Extraction

If you need to modify the tokens or make additional API calls after the token exchange, implement the getCredentialsFromTokenResponse method:

// File: auth/get-credentials-from-token-response.js
exports.getCredentialsFromTokenResponse = async function({
  connectorParameters,
  connectionParameters,
  queryParameters,
  tokenResponse
}) {
  // You can transform the token response or make additional API calls

  // For example, get user information
  const userInfoResponse = await fetch('https://api.example.com/userinfo', {
    headers: {
      'Authorization': `Bearer ${tokenResponse.access_token}`
    }
  });

  const userInfo = await userInfoResponse.json();

  // Return combined credentials
  return {
    // Include fields from token response if needed
    access_token: tokenResponse.access_token,
    refresh_token: tokenResponse.refresh_token,
    // Add custom fields
    userId: userInfo.id,
    userName: userInfo.name
  };
};

Custom Token Refresh

See refreshCredentials for more details.

If the API uses a non-standard token refresh mechanism, implement the refreshCredentials method:

// File: auth/refresh-credentials.js
exports.refreshCredentials = async function({
  connectorParameters,
  connectionParameters,
  credentials
}) {
  // Custom implementation for refreshing tokens
  const response = await fetch(connectorParameters.tokenUri, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({
      grant_type: 'refresh_token',
      refresh_token: credentials.refresh_token,
      client_id: connectorParameters.clientId,
      client_secret: connectorParameters.clientSecret
      // Add any custom parameters here
    })
  });

  const refreshResponse = await response.json();

  // Return the new credentials (they will be merged with existing credentials)
  return {
    access_token: refreshResponse.access_token,
    // Include refresh_token if it was returned
    refresh_token: refreshResponse.refresh_token || credentials.refresh_token,
    // Update expiration if available
    expires_at: refreshResponse.expires_in
      ? Date.now() + (refreshResponse.expires_in * 1000)
      : undefined
  };
};