# Authentication Flow

> Current Froomle documentation · [View canonical page](https://docs.froomle.com/froomle-doc-main/v2/guide/topics/authentication-flow.html)

Froomle APIs documented as authenticated use OAuth 2.0 Bearer tokens for machine-to-machine authentication. This page defines the public authentication contract for manual and custom API integrations.

> **NOTE:**
> 
> Frontend SDK users should follow [SDK Recommendation Authentication](https://docs.froomle.com/froomle-doc-main/v2/js_lib/jslib.html#RecoAuth) for browser token configuration. The SDK still obtains recommendation tokens from a trusted backend; never expose OAuth client credentials in browser code.

> **IMPORTANT:**
> 
> Events API calls are unauthenticated. Do not send the bearer token described on this page with event requests.

Use the public Froomle authentication endpoint for your tenant:

```text
POST https://<tenant>.froomle.com/oauth/token
```

<a id="_required_token_request_contract"></a>

## Required token request contract

Request tokens with the OAuth 2.0 Client Credentials flow.

| Field | Required | Value |
| --- | --- | --- |
| `client_id` | Yes | The client ID provided by Froomle. |
| `client_secret` | Yes | The client secret provided by Froomle. Keep this secret on your backend. |
| `grant_type` | Yes | `client_credentials` |

Send the token request as `application/x-www-form-urlencoded`:

```console
curl -X POST "https://<tenant>.froomle.com/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "grant_type=client_credentials" \
  --data-urlencode "client_id=<your_client_id>" \
  --data-urlencode "client_secret=<your_client_secret>"
```

<a id="_scope_and_audience_behavior"></a>

## Scope and audience behavior

Froomle assigns API permissions to your client credentials. The issued token contains the scopes that are configured for that client.

Do not send a `scope` parameter when requesting a token. Requested scopes are not how Froomle grants API access. Froomle grants access by the client credentials that were provisioned for your integration.

Do not send an `audience` parameter. The token audience is configured by Froomle for the tenant project.

| Parameter | Contract |
| --- | --- |
| `scope` | Omit it. Access scopes are assigned to the client credentials by Froomle. |
| `audience` | Omit it. The audience is assigned by Froomle. |

> **NOTE:**
> 
> Sending `scope` or `audience` in the token request does not grant extra API access. API access is controlled by the client credentials that Froomle provides.

<a id="_token_response"></a>

## Token response

A successful token response contains an access token:

```json
{
  "access_token": "...",
  "expires_in": 86400,
  "scope": "environment:* full:all",
  "token_type": "Bearer"
}
```

Use the `access_token` value as a Bearer token on subsequent API requests:

```console
curl -X GET "https://<tenant>.froomle.com/api/<environment>/recommendations" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json"
```

The token is a JWT signed by Froomle’s tenant authentication service. Treat the token as a credential and do not expose it unnecessarily.

<a id="_token_lifetime_and_refresh"></a>

## Token lifetime and refresh

Proper token handling is required for reliable production integrations.

-   Tokens are valid for a limited time. The default lifetime is 24 hours.
    
-   Cache and reuse a token until it is close to expiry.
    
-   Refresh proactively from your backend. A refresh interval of about 10 minutes is a safe default for most integrations.
    
-   If an API request returns `401 Unauthorized`, request a new token and retry once before surfacing the error.
    
-   Never cache tokens indefinitely.
    

<a id="_jwks_endpoint"></a>

## JWKS endpoint

If your backend needs to validate Froomle-issued tokens itself, use the public JWKS endpoint for the tenant:

```text
GET https://<tenant>.froomle.com/.well-known/jwks.json
```

Most customer integrations only call Froomle APIs and do not need to validate tokens locally. If you do validate tokens, cache the JWKS response and refresh it when token validation fails because signing keys can rotate.

<a id="_integration_strategies"></a>

## Integration strategies

<a id="_backend_integration_recommended"></a>

### Backend integration (recommended)

If you have a server-side backend, use the Client Credentials flow. Store `client_id` and `client_secret` only on your backend. Your backend requests a Bearer token from Froomle and applies it to API calls.

<a id="_hybrid_integration_with_a_minimal_backend"></a>

### Hybrid integration with a minimal backend

For browser applications that have a minimal backend:

-   Store OAuth credentials on your backend.
    
-   Request and refresh tokens on the backend.
    
-   Expose only a short-lived active token to your frontend when the frontend must call an authenticated recommendation endpoint.
    
-   Never expose `client_secret` in browser code, mobile apps, or static assets.
    

<a id="_frontend_sdk_recommendation_auth"></a>

### Frontend SDK recommendation auth

The frontend SDK has a method-specific authentication interface. Keep OAuth credentials on your backend, then follow [Recommendation Authentication](https://docs.froomle.com/froomle-doc-main/v2/js_lib/jslib.html#RecoAuth) for token delivery and timing rules. SDK recommendation authentication never applies to tracked events.

<a id="_pure_frontend_integration"></a>

### Pure frontend integration

Do not request OAuth tokens directly from a browser. Calling `/oauth/token` from frontend code would expose credentials or tokens to visitors.

If your integration has no backend component, Froomle can provide domain-based verification for supported frontend use cases. Contact your account manager to enable this.

For DNS and SDK configuration when using a custom subdomain, see [Custom domain (CNAME)](https://docs.froomle.com/froomle-doc-main/v2/guide/topics/custom-domain-cname.html).

<a id="_contract_summary"></a>

## Contract summary

The Froomle authentication contract is:

-   `POST https://<tenant>.froomle.com/oauth/token`
    
-   OAuth 2.0 Client Credentials
    
-   `client_id`, `client_secret`, and `grant_type=client_credentials`
    
-   Bearer token response with `access_token`
    
-   APIs documented as authenticated receive `Authorization: Bearer <access_token>`
    
-   Events API requests remain unauthenticated
    

<a id="_related_topics"></a>

## Related topics

-   [Authentication API Reference](https://docs.froomle.com/froomle-doc-main/v2/api_reference/authentication/authentication.html)
    
-   [Account setup](https://docs.froomle.com/froomle-doc-main/v2/guide/account-setup.html)
    
-   [Custom domain (CNAME)](https://docs.froomle.com/froomle-doc-main/v2/guide/topics/custom-domain-cname.html)
    
-   [Frontend SDK recommendation authentication](https://docs.froomle.com/froomle-doc-main/v2/js_lib/jslib.html#RecoAuth)
    
-   [Manual Recommendation Integration](https://docs.froomle.com/froomle-doc-main/v2/guide/manual-integration/recommendations.html)
