Skip to main content

Auth0 FGA Logging

Overview

The Auth0 Fine-Grained Authorization (FGA) Logs enable users to query access logs that capture all operations across all Auth0 FGA public endpoints. These logs help with:

  • Security: Identify who made changes to permissions.
  • Monitoring and compliance: Ensure authorization policies behave as expected.
  • Operational analysis: Inspect recent API activity to troubleshoot and optimize your implementation.

Key Features

  • Log Retention: Logs are retained for 7 days.
  • Rate-Limits by tier:
    • Free: 1 RPS
    • Enterprise: 8 RPS
  • Access methods:
    • Dashboard: View, filter, and search logs through the dashboard interface.
    • API: Programmatic retrieval of logs for integration with external analytics tools. To retrieve logs, your API token must have the Search logs permission set enabled via the FGA Management Dashboard (see screenshot below). Logs are retrieved using the same authentication mechanism as other FGA APIs.

Image showing the search logs store client scope


View Logs in the Dashboard

The Logs section in the FGA Management Dashboard allows you to inspect your store activity, enabling you to search and filter logs without manual API calls. The search box in the Dashboard supports the same Lucene query syntax as the API's query parameter, so you can use any of the query patterns documented below.

  1. Navigate to your Store in the FGA Dashboard.
  2. Select Logs from the left-hand sidebar.
  3. Use the search box to filter logs using query syntax (e.g., request.operation:"Write"), and/or use the date range picker to constrain results.
  4. Select any log entry to view the full details in the right-hand panel, including all request fields, response metadata, and the raw JSON payload. This is a convenient way to discover queryable field names for each operation type.

Image showing logs in Dashboard

Logging API

The Logging API is designed to provide authorization activity in a standardized format for developers, platform engineers, and compliance teams.

Log schema

Each log entry captures request metadata, response details, and operation-specific payload. Below is a sample for the Write() endpoint:

{
"timestamp": "2025-03-11T15:51:37.457Z",
"region": "us-east-1",
"request.id": "01JBCFKDVGMV2WH0RVPFDD7YXG",
"request.duration": "658.455µs",
"request.operation": "Write",
"request.user_agent": "Go-SDK 1.2.3",
"request.client_id": "gxcObq3LuTTfX4sczYGUzzDK7efifg2FITc",
"request.authorization_model_id": "01JM23XPZT17STV45MQDSVAGNP",
"request.store_id": "01JM23Y8QEJJH4KP526KXFRKVR",
"request.account_id": "01JM23Z434H9TDXYBG5QQHMBKZ",
"request.actor_id": "user:actor-id",
"request.actor_ip": "192.168.1.100",
"request.correlation_id": "0ae9b241738f3f53f5758db39da8c2f2",
"request.writes": [
{
"tuple_key": {
"user": "user:anne",
"relation": "reader",
"object": "document:2021-budget"
},
"condition": {
"name": "condition1",
"context": {
"grant_time": "2023-05-08T12:00:00Z"
}
}
}
],
"response.headers": {
"FGA-Query-Duration-MS": "0",
"FGA-Request-Id": "3c8b9aba6b3aa428b0cb1f5cb1d7a301",
"Openfga-Authorization-Model-Id": "01JZMWHZ11833P6GZHYTKXYGKJS",
"x-ratelimit-limit": "20",
"x-ratelimit-remaining": "19",
"x-ratelimit-reset": "1751974302"
},
"request.deletes": [
{
"tuple_key": {
"user": "user:anne",
"relation": "reader",
"object": "document:2021-budget"
}
}
],
"response.status_code": 200
}

All FGA API operations are logged and follow the same general structure, with operation-specific payload fields. For example, Write logs include request.writes and request.deletes arrays, while Check logs include request.tuple_key fields.

Supported Query Parameters

The Auth0 FGA Logging API allows you to filter and retrieve logs using a set of query parameters. These parameters enable you to narrow down your search and analyze log data efficiently.

ParameterDescriptionTypeValuesRequired / Optional
start_timeStart time for the period of interest. Ignored if continuation_token is provided.stringISO 8601 (RFC3339) Date-Time in UTC. Must be within the last 7 days from the current time.Optional (default: now - 7 days)
end_timeEnd time for the period of interest. Ignored if continuation_token is provided.stringISO 8601 (RFC3339) Date-Time in UTC. Must be >= start_time.Optional (default: now)
page_sizeNumber of entries to return.numberMinimum: 1. Maximum: 100.Optional (default: 50)
continuation_tokenOpaque cursor for fetching the next page. Omit (or leave blank) on the first request. Takes precedence over start_time when both are provided.stringAn opaque token carrying the full pagination context.Optional
querySearch criteria using Lucene-like query string syntax. Values containing a colon must be quoted, e.g., 'user:Anne'.stringFor example, request.client_id:ABC123.Optional
sortSort order for the results based on timestamp. Ignored if continuation_token is provided.stringtimestamp:1 (ascending) or timestamp:-1 (descending).Optional (default: timestamp:1)

Log Search Query Syntax

When searching for logs, you can create queries using a subset of Lucene query syntax to refine your search.

  • A term can be a single word such as jane or smith.
  • A term can be a phrase in single quotes ('customer log').
  • Multiple terms can be grouped with parentheses to form sub-queries.
  • All search fields are case sensitive.
  • Operators (AND, OR, NOT) work on all searchable fields.

Supported Operations

The request.operation field identifies the API operation that generated the log entry. The following values are valid:

OperationDescription
ReadRead relationship tuples
WriteWrite relationship tuples
CheckCheck authorization
ExpandExpand relationship paths
ListObjectsList objects a user has access to
StreamedListObjectsStreamed list objects
ListUsersList users with access to an object
BatchCheckBatch authorization checks
ReadChangesRead relationship tuple changes (watch)
ReadAuthorizationModelsList authorization models
ReadAuthorizationModelRead a specific authorization model
WriteAuthorizationModelWrite an authorization model
ReadAssertionsRead model assertions
WriteAssertionsWrite model assertions

Each operation type has its own schema. Some fields are shared across all operations (such as request.id, request.client_id, and response.status_code), while others are specific to an operation (such as request.writes for Write or request.tuple_key for Check).

Common Searchable Fields

The following fields are shared across all or most log entries and can be used in queries:

Request metadata:

FieldDescription
request.idUnique request identifier
request.operationOperation type (see Supported Operations)
request.durationRequest duration
request.store_idStore ID
request.account_idAccount ID
request.client_idClient ID
request.authorization_model_idAuthorization model ID
request.user_agentSDK or client user agent string

Contextual headers (set by the caller):

FieldDescription
request.actor_idActor or user identifier (set via X-FGA-Actor-ID header)
request.actor_ipIP address of actor (set via X-FGA-Forwarded-For header)
request.correlation_idCorrelation ID for request tracking (set via X-Correlation-ID header)

Operation-specific fields (examples):

FieldApplicable Operations
request.tuple_key.userCheck, Read, ListObjects, ListUsers, Expand
request.tuple_key.relationCheck, Read, ListObjects, ListUsers, Expand
request.tuple_key.objectCheck, Read, ListObjects, ListUsers, Expand
request.writesWrite
request.deletesWrite

Response and other fields:

FieldDescription
response.status_codeHTTP response status code
timestampRequest timestamp (ISO 8601)
regionGeographic region
Discovering additional fields

This is not an exhaustive list. Each operation may include additional fields specific to its request and response schema. To discover all available fields for a given operation:

  1. Filter logs by operation — via the API (query=request.operation:Check) or the Dashboard search box.
  2. Inspect the returned log entries, or click a log row in the Dashboard to view the full details panel and raw JSON payload.
  3. Use the field paths you find (e.g., request.tuple_key.object) to build more specific queries.

Query Examples

To retrieve logs, send a GET request to the /stores/{store_id}/logs endpoint.

Before you begin:

  1. Obtain your API token to call the Logging API.
  2. Set environment variables:
export FGA_API_URL="https://api.us1.fga.dev"
export FGA_STORE_ID="your_store_id"
export ACCESS_TOKEN="your_api_token"

Examples:

  1. Use defaults (last 7 days to now)
curl "$FGA_API_URL/stores/$FGA_STORE_ID/logs" -H "authorization: bearer $ACCESS_TOKEN"
  1. Filter by Time Range
curl "$FGA_API_URL/stores/$FGA_STORE_ID/logs?start_time=2025-07-03T15:11:11Z&end_time=2025-07-09T15:11:11Z" -H "authorization: bearer $ACCESS_TOKEN"
  1. Filter by Operation
curl "$FGA_API_URL/stores/$FGA_STORE_ID/logs?query=request.operation:Write" -H "authorization: bearer $ACCESS_TOKEN"
  1. Filter by Tuple keys (user value)
curl "$FGA_API_URL/stores/$FGA_STORE_ID/logs?query=request.tuple_key.user:'user:Anne'" -H "authorization: bearer $ACCESS_TOKEN"
  1. Paginate results
  • First page (optionally constrain the window and page size):
curl "$FGA_API_URL/stores/$FGA_STORE_ID/logs?page_size=50" -H "authorization: bearer $ACCESS_TOKEN"
  • Next page (use the continuation_token returned from the previous response):
curl "$FGA_API_URL/stores/$FGA_STORE_ID/logs?continuation_token=<TOKEN_FROM_PREVIOUS_RESPONSE>" -H "authorization: bearer $ACCESS_TOKEN"

Note: When passing a continuation_token along with start_time, the continuation_token takes precedence.

  1. Retrieve results in descending order (most recent first):
curl "$FGA_API_URL/stores/$FGA_STORE_ID/logs?sort=timestamp:-1" -H "authorization: bearer $ACCESS_TOKEN"

Note: When passing a continuation_token along with sort, the continuation_token takes precedence.

  1. Combine conditions with AND
curl "$FGA_API_URL/stores/$FGA_STORE_ID/logs?query=request.operation:Check AND response.status_code:200" -H "authorization: bearer $ACCESS_TOKEN"
  1. Exclude results with -
curl "$FGA_API_URL/stores/$FGA_STORE_ID/logs?query=-request.operation:ReadAuthorizationModels" -H "authorization: bearer $ACCESS_TOKEN"
  1. Filter by response status code
curl "$FGA_API_URL/stores/$FGA_STORE_ID/logs?query=response.status_code:400" -H "authorization: bearer $ACCESS_TOKEN"
  1. Filter by client ID
curl "$FGA_API_URL/stores/$FGA_STORE_ID/logs?query=request.client_id:ABC123" -H "authorization: bearer $ACCESS_TOKEN"
  1. Filter by actor
curl "$FGA_API_URL/stores/$FGA_STORE_ID/logs?query=request.actor_id:'user:admin-service'" -H "authorization: bearer $ACCESS_TOKEN"

Setting Contextual Parameters as Headers

You can pass optional contextual headers with each request to provide richer traceability and auditing context:

  • Actor ID (X-FGA-Actor-ID): Identifies the user or service principal initiating the API request that could affect authorization data. Example: "X-FGA-Actor-ID": "user-123" or "X-FGA-Actor-ID": "service-account-billing-job".

  • IP Address (X-FGA-Forwarded-For): Captures the originating IP address of the actor making the request. Example: "X-FGA-Forwarded-For": "192.123.1.1".

  • Correlation ID (X-Correlation-ID): A unique identifier provided by the calling application to track a single logical operation across multiple services or requests. Example: "X-Correlation-ID": "abc234-dfg345-jhk3"

These values are captured in the Logging API schema under:

  • X-FGA-Actor-IDrequest.actor_id

  • X-FGA-Forwarded-Forrequest.actor_ip

  • X-Correlation-IDrequest.correlation_id

Below is a reference code snippet showing how to pass these headers:

Initialize the SDK
// Checkout the "How to Setup the SDK Client" page for more details.
const { CredentialsMethod, OpenFgaClient } = require('@openfga/sdk'); // OR import { CredentialsMethod, OpenFgaClient } from '@openfga/sdk';

// Ensure the environment variables are set
// FGA_API_URL = 'https://api.us1.fga.dev' // 'https://api.eu1.fga.dev' for EU and 'https://api.au1.fga.dev' for AU
// FGA_STORE_ID = 'YOUR_STORE_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_MODEL_ID = 'YOUR_MODEL_ID' - optional, can be overridden per request, helps reduce latency
// FGA_API_TOKEN_ISSUER = 'auth.fga.dev'
// FGA_API_AUDIENCE = 'https://api.us1.fga.dev/' // 'https://api.eu1.fga.dev/' for EU and 'https://api.au1.fga.dev/' for AU
// FGA_CLIENT_ID = 'YOUR_CLIENT_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_CLIENT_SECRET = 'YOUR_CLIENT_SECRET' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page

const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID,
credentials: { // Credentials are not needed if connecting to the Playground API
method: CredentialsMethod.ClientCredentials,
config: {
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER,
apiAudience: process.env.FGA_API_AUDIENCE,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
},
},
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne3',
relation: 'viewer',
object: 'document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a',
}, {
authorizationModelId: '01HVMMBCMGZNT3SED4Z17ECXCA',
headers: {
"X-FGA-Actor-ID": "auth0|64cbb8c4c79cacf57b8b9ee7",
"X-FGA-Forwarded-For": "192.168.1.100",
"X-Correlation-ID": "0ae9b241738f3f53f5758db39da8c2f2",
},
});

// allowed = true

The Logging API won't have CLI or SDK support; you should use direct REST calls to call this API.

Export Logs to External Systems

You can build automated scripts to export FGA logs to external data sinks for long-term storage, analytics, or compliance purposes. The examples below demonstrate polling the Logging API and saving logs to local files in JSONL format.

Important considerations:

  • The polling frequency in these examples is set to 1 hour - adjust this based on your use case and rate limits
  • Consider your tier's rate limits when setting polling intervals (Free: 1 RPS, Enterprise: 8 RPS)
  • Logs are retained for 7 days, so ensure your export frequency captures all necessary data
  • Each example handles pagination using continuation tokens to retrieve all available logs
import fs from 'node:fs';
import fetch from 'node-fetch'; // If using Node < 18 add dependency

const BASE_URL = process.env.FGA_API_URL || 'https://api.us1.fga.dev';
const STORE_ID = process.env.FGA_STORE_ID;
const TOKEN = process.env.FGA_API_TOKEN; // Bearer token
const FILE = 'logs_' + STORE_ID + '.jsonl';

if (!STORE_ID || !TOKEN) {
console.error('Missing FGA_STORE_ID or FGA_API_TOKEN');
process.exit(1);
}

async function pollOnce(continuation) {
const url = new URL(BASE_URL + '/stores/' + STORE_ID + '/logs');
if (continuation) url.searchParams.set('continuation_token', continuation);
const res = await fetch(url.toString(), {
headers: { Authorization: 'Bearer ' + TOKEN, Accept: 'application/json' },
});
if (!res.ok) {
console.error('API error', await res.text());
return null;
}
return res.json();
}

async function pollLoop() {
console.log('Polling logs...');
let continuation = null;
let total = 0;
while (true) {
const data = await pollOnce(continuation);
if (!data || !data.logs || data.logs.length === 0) break;
const lines = data.logs.map(l => JSON.stringify(l)).join('\n') + '\n';
fs.appendFileSync(FILE, lines);
total += data.logs.length;
continuation = data.continuation_token || null;
if (!continuation) break;
}
console.log('Saved ' + total + ' logs to ' + FILE);
}

(async () => {
while (true) {
await pollLoop();
await new Promise(r => setTimeout(r, 3600_000));
}
})();

Have Feedback?

You can use any of our support channels for any questions or suggestions you may have.