stemp Logostemp Developer

Authentication

How to authenticate with the stemp API using OAuth2 tokens and API keys.

Authentication

The stemp API supports two authentication methods: OAuth2 tokens (for third-party apps) and API tokens (for server-to-server integrations). All API requests must include valid credentials.

Authentication Methods

MethodUse CaseHeader Format
OAuth2 Bearer TokenThird-party apps acting on behalf of an organizationAuthorization: Bearer <access_token>
API TokenYour own backend services and scriptsAuthorization: Bearer <api_token>

Access Tokens

After completing the OAuth2 flow, you receive an access token. Include it in the Authorization header:

Authorization: Bearer <access_token>

Token Properties

PropertyDetails
FormatJWT (RS256 signed)
Expiration30 minutes (1800 seconds)
Audiencestemp:api:app
ClaimsinstallationId, organizationId, clientId, scopes

Token Lifecycle

OAuth2 Flow → Access Token (30 min) → Expires → Refresh → New Access Token

                                        Refresh Token (30 days) ──┘

Refreshing Tokens

When an access token expires, use the refresh token to get a new one:

curl -X POST https://api.stemp.app/api/v1/apps/oauth2/refresh \
  -H "Content-Type: application/json" \
  -d '{
    "refresh_token": "srt_your_refresh_token"
  }'

The response includes a new access token:

{
  "access_token": "eyJhbGciOiJSUzI1NiJ9...",
  "token_type": "bearer",
  "expires_in": 1800,
  "scope": "pass:read pass:create loyalty:manage",
  "refresh_token": null
}

If refresh_token is not null, your existing refresh token is being rotated — start using the new one. Refresh tokens are valid for 30 days.

API Tokens

For server-to-server integrations that don't require the OAuth2 flow, use API tokens. They work the same way in the Authorization header:

Authorization: Bearer sk_live_abc123...

Error Responses

StatusMeaningWhat to Do
401 UnauthorizedToken is missing, expired, or invalidRefresh the token or re-authenticate
403 ForbiddenToken is valid but lacks the required scopeRequest additional scopes or use a different token

Example 401 Response

{
  "error": {
    "code": "unauthorized",
    "message": "Access token is expired"
  }
}

Automatic Token Refresh

Implement automatic token refresh in your application to handle expiration seamlessly:

let accessToken = '...'
let refreshToken = 'srt_...'

async function authenticatedFetch(url: string, options: RequestInit = {}) {
  let response = await fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      Authorization: `Bearer ${accessToken}`,
    },
  })

  if (response.status === 401) {
    // Token expired — refresh it
    const refreshResponse = await fetch('https://api.stemp.app/api/v1/apps/oauth2/refresh', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ refresh_token: refreshToken }),
    })

    const tokens = await refreshResponse.json()
    accessToken = tokens.access_token
    if (tokens.refresh_token) {
      refreshToken = tokens.refresh_token
    }

    // Retry the original request
    response = await fetch(url, {
      ...options,
      headers: {
        ...options.headers,
        Authorization: `Bearer ${accessToken}`,
      },
    })
  }

  return response
}

Security Best Practices

  • Store tokens securely — never expose them in client-side code, URLs, or logs.
  • Use short-lived access tokens — the 30-minute expiration limits the damage from token leaks.
  • Refresh proactively — refresh tokens before they expire to avoid request failures.
  • Request only the scopes your application needs — follow the principle of least privilege.
  • Monitor for 401 responses — implement automatic refresh logic rather than failing on expired tokens.