> ## Documentation Index
> Fetch the complete documentation index at: https://openfga.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Check user authorization

> The Check API returns whether a given user has a relationship with a given object in a given store.

The `user` field of the request can be a specific target, such as `user:anne`, or a userset (set of users) such as `group:marketing#member` or a type-bound public access `user:*`.
To arrive at a result, the API uses:

- An [authorization model](/docs/getting-started/configure-model)

- Explicit tuples written through the Write API

- Contextual tuples present in the request

- Implicit tuples that exist by virtue of applying set theory

For example: `document:2021-budget#viewer@document:2021-budget#viewer`. In this example, the set of users who are viewers of `document:2021-budget` are the set of users who are the viewers of `document:2021-budget`.

A `contextual_tuples` object may also be included in the body of the request. This object contains one field `tuple_keys`, which is an array of tuple keys. Each of these tuples may have an associated `condition`.
You may also provide an `authorization_model_id` in the body. This is used to assert that the input `tuple_key` is valid for the model specified. If not specified, the assertion is made against the latest authorization model ID.

> **Note:** We recommend you specify authorization model id for better performance.

You may also provide a `context` object that is used to evaluate the conditioned tuples in the system.

> **Note:** We recommend you provide a value for all the input parameters of all the conditions, to ensure that all tuples be evaluated correctly.

By default, the Check API caches results for a short time to optimize performance. You may specify a value of `HIGHER_CONSISTENCY` for the optional `consistency` parameter in the body to inform the server that higher conisistency is preferred at the expense of increased latency. Consideration should be given to the increased latency if requesting higher consistency.
The response returns whether the relationship exists in the field `allowed`.

Some exceptions apply, but in general, if a Check API responds with `{allowed: true}`, then you can expect the equivalent ListObjects query to return the object, and viceversa. 
For example, if `Check(user:anne, reader, document:2021-budget)` responds with `{allowed: true}`, then `ListObjects(user:anne, reader, document)` may include `document:2021-budget` in the response.
## Examples

### Querying with contextual tuples

In order to check if user `user:anne` of type `user` has a `reader` relationship with object `document:2021-budget` given the following contextual tuple:
```json
{
  "user": "user:anne",
  "relation": "member",
  "object": "time_slot:office_hours"
}
```
the Check API can be used with the following request body:
```json
{
  "tuple_key": {
    "user": "user:anne",
    "relation": "reader",
    "object": "document:2021-budget"
  },
  "contextual_tuples": {
    "tuple_keys": [
      {
        "user": "user:anne",
        "relation": "member",
        "object": "time_slot:office_hours"
      }
    ]
  },
  "authorization_model_id": "01G50QVV17PECNVAHX1GG4Y5NC"
}
```
### Querying usersets

Some Checks always return `true`, even without any tuples. For example, for the following authorization model:
```python
model
  schema 1.1
type user
type document
  relations
    define reader: [user]
```
the following query:
```json
{
  "tuple_key": {
     "user": "document:2021-budget#reader",
     "relation": "reader",
     "object": "document:2021-budget"
  }
}
```
always returns `{ "allowed": true }`. This is because usersets are self-defining: the userset `document:2021-budget#reader` always has the `reader` relation with `document:2021-budget`.
### Querying usersets with difference in the model

A Check for a userset can yield results that must be treated carefully if the model involves difference. For example, for the following authorization model:
```python
model
  schema 1.1
type user
type group
  relations
    define member: [user]
type document
  relations
    define blocked: [user]
    define reader: [group#member] but not blocked
```
the following query:
```json
{
  "tuple_key": {
     "user": "group:finance#member",
     "relation": "reader",
     "object": "document:2021-budget"
  },
  "contextual_tuples": {
    "tuple_keys": [
      {
        "user": "user:anne",
        "relation": "member",
        "object": "group:finance"
      },
      {
        "user": "group:finance#member",
        "relation": "reader",
        "object": "document:2021-budget"
      },
      {
        "user": "user:anne",
        "relation": "blocked",
        "object": "document:2021-budget"
      }
    ]
  },
}
```
returns `{ "allowed": true }`, even though a specific user of the userset `group:finance#member` does not have the `reader` relationship with the given object.
### Requesting higher consistency

By default, the Check API caches results for a short time to optimize performance. You may request higher consistency to inform the server that higher consistency should be preferred at the expense of increased latency. Care should be taken when requesting higher consistency due to the increased latency.
```json
{
  "tuple_key": {
     "user": "group:finance#member",
     "relation": "reader",
     "object": "document:2021-budget"
  },
  "consistency": "HIGHER_CONSISTENCY"
}
```




## OpenAPI

````yaml https://raw.githubusercontent.com/openfga/api/refs/heads/main/docs/openapiv3/apidocs.openapi.json post /stores/{store_id}/check
openapi: 3.0.3
info:
  contact:
    email: community@openfga.dev
    name: OpenFGA
    url: https://openfga.dev
  description: >-
    A high performance and flexible authorization/permission engine built for
    developers and inspired by Google Zanzibar.
  license:
    name: Apache-2.0
    url: https://github.com/openfga/openfga/blob/main/LICENSE
  title: OpenFGA
  version: 1.x
servers: []
security: []
tags:
  - name: AuthZenService
  - name: OpenFGAService
paths:
  /stores/{store_id}/check:
    post:
      tags:
        - Relationship Queries
      summary: Check user authorization
      description: >
        The Check API returns whether a given user has a relationship with a
        given object in a given store.


        The `user` field of the request can be a specific target, such as
        `user:anne`, or a userset (set of users) such as
        `group:marketing#member` or a type-bound public access `user:*`.

        To arrive at a result, the API uses:


        - An [authorization model](/docs/getting-started/configure-model)


        - Explicit tuples written through the Write API


        - Contextual tuples present in the request


        - Implicit tuples that exist by virtue of applying set theory


        For example: `document:2021-budget#viewer@document:2021-budget#viewer`.
        In this example, the set of users who are viewers of
        `document:2021-budget` are the set of users who are the viewers of
        `document:2021-budget`.


        A `contextual_tuples` object may also be included in the body of the
        request. This object contains one field `tuple_keys`, which is an array
        of tuple keys. Each of these tuples may have an associated `condition`.

        You may also provide an `authorization_model_id` in the body. This is
        used to assert that the input `tuple_key` is valid for the model
        specified. If not specified, the assertion is made against the latest
        authorization model ID.


        > **Note:** We recommend you specify authorization model id for better
        performance.


        You may also provide a `context` object that is used to evaluate the
        conditioned tuples in the system.


        > **Note:** We recommend you provide a value for all the input
        parameters of all the conditions, to ensure that all tuples be evaluated
        correctly.


        By default, the Check API caches results for a short time to optimize
        performance. You may specify a value of `HIGHER_CONSISTENCY` for the
        optional `consistency` parameter in the body to inform the server that
        higher conisistency is preferred at the expense of increased latency.
        Consideration should be given to the increased latency if requesting
        higher consistency.

        The response returns whether the relationship exists in the field
        `allowed`.


        Some exceptions apply, but in general, if a Check API responds with
        `{allowed: true}`, then you can expect the equivalent ListObjects query
        to return the object, and viceversa. 

        For example, if `Check(user:anne, reader, document:2021-budget)`
        responds with `{allowed: true}`, then `ListObjects(user:anne, reader,
        document)` may include `document:2021-budget` in the response.

        ## Examples


        ### Querying with contextual tuples


        In order to check if user `user:anne` of type `user` has a `reader`
        relationship with object `document:2021-budget` given the following
        contextual tuple:

        ```json

        {
          "user": "user:anne",
          "relation": "member",
          "object": "time_slot:office_hours"
        }

        ```

        the Check API can be used with the following request body:

        ```json

        {
          "tuple_key": {
            "user": "user:anne",
            "relation": "reader",
            "object": "document:2021-budget"
          },
          "contextual_tuples": {
            "tuple_keys": [
              {
                "user": "user:anne",
                "relation": "member",
                "object": "time_slot:office_hours"
              }
            ]
          },
          "authorization_model_id": "01G50QVV17PECNVAHX1GG4Y5NC"
        }

        ```

        ### Querying usersets


        Some Checks always return `true`, even without any tuples. For example,
        for the following authorization model:

        ```python

        model
          schema 1.1
        type user

        type document
          relations
            define reader: [user]
        ```

        the following query:

        ```json

        {
          "tuple_key": {
             "user": "document:2021-budget#reader",
             "relation": "reader",
             "object": "document:2021-budget"
          }
        }

        ```

        always returns `{ "allowed": true }`. This is because usersets are
        self-defining: the userset `document:2021-budget#reader` always has the
        `reader` relation with `document:2021-budget`.

        ### Querying usersets with difference in the model


        A Check for a userset can yield results that must be treated carefully
        if the model involves difference. For example, for the following
        authorization model:

        ```python

        model
          schema 1.1
        type user

        type group
          relations
            define member: [user]
        type document
          relations
            define blocked: [user]
            define reader: [group#member] but not blocked
        ```

        the following query:

        ```json

        {
          "tuple_key": {
             "user": "group:finance#member",
             "relation": "reader",
             "object": "document:2021-budget"
          },
          "contextual_tuples": {
            "tuple_keys": [
              {
                "user": "user:anne",
                "relation": "member",
                "object": "group:finance"
              },
              {
                "user": "group:finance#member",
                "relation": "reader",
                "object": "document:2021-budget"
              },
              {
                "user": "user:anne",
                "relation": "blocked",
                "object": "document:2021-budget"
              }
            ]
          },
        }

        ```

        returns `{ "allowed": true }`, even though a specific user of the
        userset `group:finance#member` does not have the `reader` relationship
        with the given object.

        ### Requesting higher consistency


        By default, the Check API caches results for a short time to optimize
        performance. You may request higher consistency to inform the server
        that higher consistency should be preferred at the expense of increased
        latency. Care should be taken when requesting higher consistency due to
        the increased latency.

        ```json

        {
          "tuple_key": {
             "user": "group:finance#member",
             "relation": "reader",
             "object": "document:2021-budget"
          },
          "consistency": "HIGHER_CONSISTENCY"
        }

        ```
      operationId: Check
      parameters:
        - in: path
          name: store_id
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CheckBody'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CheckResponse'
          description: A successful response.
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorMessageResponse'
          description: Request failed due to invalid input.
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthenticatedResponse'
          description: Not authenticated.
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenResponse'
          description: Forbidden.
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PathUnknownErrorMessageResponse'
          description: Request failed due to incorrect path.
        '409':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AbortedMessageResponse'
          description: Request was aborted due a transaction conflict.
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableContentMessageResponse'
          description: Request timed out due to excessive request throttling.
        '500':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InternalErrorMessageResponse'
          description: Request failed due to internal server error.
      x-codeSamples:
        - lang: node
          label: Node.js
          source: >-
            const { OpenFgaClient, ConsistencyPreference } =
            require('@openfga/sdk');


            const fgaClient = new OpenFgaClient({
              apiUrl: process.env.FGA_API_URL,
              storeId: process.env.FGA_STORE_ID,
              authorizationModelId: process.env.FGA_MODEL_ID, // Optional; requests can override this.
            });


            async function main() {
                const body = {
                  "user": "user:anne",
                  "relation": "reader",
                  "object": "document:budget"
                };
                const options = {
                
                };
                const response = await fgaClient.check(body, options);
            }


            main().catch((error) => {
                console.error(error);
                process.exitCode = 1;
            });
        - lang: go
          label: Go
          source: |-
            package main

            import (
                "context"
                "os"

                . "github.com/openfga/go-sdk/client"
            )

            func main() {
                fgaClient, err := NewSdkClient(&ClientConfiguration{
                    ApiUrl: os.Getenv("FGA_API_URL"),
                    StoreId: os.Getenv("FGA_STORE_ID"),
                    AuthorizationModelId: os.Getenv("FGA_MODEL_ID"), // Optional; requests can override this.
                })
                if err != nil {
                    panic(err)
                }
                
                body := ClientCheckRequest{
                  User: "user:anne",
                  Relation: "reader",
                  Object: "document:budget",
                }
                options := ClientCheckOptions{
                
                }
                data, err := fgaClient.Check(context.Background()).Body(body).Options(options).Execute()
                if err != nil {
                    panic(err)
                }
                _ = data
            }
        - lang: dotnet
          label: .NET
          source: |-
            using System.Collections.Generic;
            using OpenFga.Sdk.Client;
            using OpenFga.Sdk.Client.Model;
            using OpenFga.Sdk.Model;
            using Environment = System.Environment;

            var fgaClient = new OpenFgaClient(new ClientConfiguration() {
              ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"),
              StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"),
              AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_MODEL_ID"), // Optional; requests can override this.
            });

            var body = new ClientCheckRequest {
              User = "user:anne",
              Relation = "reader",
              Object = "document:budget",
            };
            var options = new ClientCheckOptions {

            };
            var response = await fgaClient.Check(body, options);
        - lang: python
          label: Python
          source: >-
            import asyncio

            import os

            from openfga_sdk.client import OpenFgaClient, ClientConfiguration

            from openfga_sdk.client.models import ClientCheckRequest,
            ClientTuple

            from openfga_sdk.models import RelationshipCondition


            async def main():
                configuration = ClientConfiguration(
                    api_url=os.environ.get("FGA_API_URL"),
                    store_id=os.environ.get("FGA_STORE_ID"),
                    authorization_model_id=os.environ.get("FGA_MODEL_ID"), # Optional; requests can override this.
                )
                async with OpenFgaClient(configuration) as fga_client:
                    body = ClientCheckRequest(
                      user="user:anne",
                      relation="reader",
                      object="document:budget",
                    )
                    options = {
                    
                    }
                    response = await fga_client.check(body, options)

            asyncio.run(main())
        - lang: java
          label: Java
          source: |-
            import dev.openfga.sdk.api.client.OpenFgaClient;
            import dev.openfga.sdk.api.configuration.ClientConfiguration;
            import dev.openfga.sdk.api.configuration.*;
            import dev.openfga.sdk.api.client.model.*;
            import dev.openfga.sdk.api.model.*;
            import java.util.List;
            import java.util.Map;
            import java.util.ArrayList;

            public class Example {
                public static void main(String[] args) throws Exception {
                    var config = new ClientConfiguration()
                        .apiUrl(System.getenv("FGA_API_URL"))
                        .storeId(System.getenv("FGA_STORE_ID"))
                        .authorizationModelId(System.getenv("FGA_MODEL_ID")); // Optional; requests can override this.
                    var fgaClient = new OpenFgaClient(config);
                    
                    var body = new ClientCheckRequest()
                      .user("user:anne")
                      .relation("reader")
                      ._object("document:budget");
                    var options = new ClientCheckOptions();
                    var response = fgaClient.check(body, options).get();
                }
            }
        - lang: bash
          label: curl
          source: >-
            # Set FGA_API_URL to the URL of your OpenFGA server.

            # Set FGA_STORE_ID to your store ID.

            # These examples use a server with authentication disabled.

            # For authenticated servers, see
            /docs/getting-started/setup-sdk-client.


            curl -X POST "$FGA_API_URL/stores/$FGA_STORE_ID/check" \
              -H "content-type: application/json" \
              -d '{
              "authorization_model_id": "'"$FGA_MODEL_ID"'",
              "tuple_key": {
                "user": "user:anne",
                "relation": "reader",
                "object": "document:budget"
              }
            }'
components:
  schemas:
    CheckBody:
      properties:
        authorization_model_id:
          example: 01G5JAVJ41T49E9TT3SKVS7X1J
          type: string
        consistency:
          allOf:
            - $ref: '#/components/schemas/ConsistencyPreference'
            - description: >-
                Controls the consistency preference for this request. Default
                value is `UNSPECIFIED`, which has the same behavior as
                `MINIMIZE_LATENCY`.
        context:
          description: >-
            Additional request context that is used to evaluate any ABAC
            conditions encountered

            in the query evaluation.
          type: object
        contextual_tuples:
          $ref: '#/components/schemas/ContextualTupleKeys'
        trace:
          description: Defaults to false. Making it true has performance implications.
          example: false
          readOnly: true
          type: boolean
        tuple_key:
          $ref: '#/components/schemas/CheckRequestTupleKey'
      required:
        - tuple_key
      type: object
    CheckResponse:
      properties:
        allowed:
          example: true
          type: boolean
        resolution:
          description: For internal use only.
          type: string
      type: object
    ValidationErrorMessageResponse:
      example:
        code: validation_error
        message: Generic validation error
      properties:
        code:
          $ref: '#/components/schemas/ErrorCode'
        message:
          type: string
      type: object
    UnauthenticatedResponse:
      example:
        code: unauthenticated
        message: unauthenticated
      properties:
        code:
          $ref: '#/components/schemas/ErrorCode'
        message:
          type: string
      type: object
    ForbiddenResponse:
      example:
        code: forbidden
        message: the principal is not authorized to perform the action
      properties:
        code:
          $ref: '#/components/schemas/AuthErrorCode'
        message:
          type: string
      type: object
    PathUnknownErrorMessageResponse:
      example:
        code: undefined_endpoint
        message: Endpoint not enabled
      properties:
        code:
          $ref: '#/components/schemas/NotFoundErrorCode'
        message:
          type: string
      type: object
    AbortedMessageResponse:
      example:
        code: '10'
        message: transaction conflict
      properties:
        code:
          type: string
        message:
          type: string
      type: object
    UnprocessableContentMessageResponse:
      example:
        code: throttled_timeout_error
        message: timeout due to throttling on complex request
      properties:
        code:
          $ref: '#/components/schemas/UnprocessableContentErrorCode'
        message:
          type: string
      type: object
    InternalErrorMessageResponse:
      example:
        code: internal_error
        message: Internal Server Error
      properties:
        code:
          $ref: '#/components/schemas/InternalErrorCode'
        message:
          type: string
      type: object
    ConsistencyPreference:
      default: UNSPECIFIED
      description: |-
        Controls the consistency preferences when calling the query APIs.

         - UNSPECIFIED: Default if not set. Behavior will be the same as MINIMIZE_LATENCY.
         - MINIMIZE_LATENCY: Minimize latency at the potential expense of lower consistency.
         - HIGHER_CONSISTENCY: Prefer higher consistency, at the potential expense of increased latency.
      enum:
        - UNSPECIFIED
        - MINIMIZE_LATENCY
        - HIGHER_CONSISTENCY
      example: MINIMIZE_LATENCY
      type: string
    ContextualTupleKeys:
      properties:
        tuple_keys:
          items:
            allOf:
              - $ref: '#/components/schemas/TupleKey'
              - type: object
          maxItems: 100
          type: array
      required:
        - tuple_keys
      type: object
    CheckRequestTupleKey:
      properties:
        object:
          example: document:2021-budget
          maxLength: 256
          type: string
        relation:
          example: reader
          maxLength: 50
          type: string
        user:
          example: user:anne
          maxLength: 512
          type: string
      required:
        - user
        - relation
        - object
      type: object
    ErrorCode:
      default: no_error
      enum:
        - no_error
        - validation_error
        - authorization_model_not_found
        - authorization_model_resolution_too_complex
        - invalid_write_input
        - cannot_allow_duplicate_tuples_in_one_request
        - cannot_allow_duplicate_types_in_one_request
        - cannot_allow_multiple_references_to_one_relation
        - invalid_continuation_token
        - invalid_tuple_set
        - invalid_check_input
        - invalid_expand_input
        - unsupported_user_set
        - invalid_object_format
        - write_failed_due_to_invalid_input
        - authorization_model_assertions_not_found
        - latest_authorization_model_not_found
        - type_not_found
        - relation_not_found
        - empty_relation_definition
        - invalid_user
        - invalid_tuple
        - unknown_relation
        - store_id_invalid_length
        - assertions_too_many_items
        - id_too_long
        - authorization_model_id_too_long
        - tuple_key_value_not_specified
        - tuple_keys_too_many_or_too_few_items
        - page_size_invalid
        - param_missing_value
        - difference_base_missing_value
        - subtract_base_missing_value
        - object_too_long
        - relation_too_long
        - type_definitions_too_few_items
        - type_invalid_length
        - type_invalid_pattern
        - relations_too_few_items
        - relations_too_long
        - relations_invalid_pattern
        - object_invalid_pattern
        - query_string_type_continuation_token_mismatch
        - exceeded_entity_limit
        - invalid_contextual_tuple
        - duplicate_contextual_tuple
        - invalid_authorization_model
        - unsupported_schema_version
        - cancelled
        - invalid_start_time
      type: string
    AuthErrorCode:
      default: no_auth_error
      enum:
        - no_auth_error
        - auth_failed_invalid_subject
        - auth_failed_invalid_audience
        - auth_failed_invalid_issuer
        - invalid_claims
        - auth_failed_invalid_bearer_token
        - bearer_token_missing
        - unauthenticated
        - forbidden
      type: string
    NotFoundErrorCode:
      default: no_not_found_error
      enum:
        - no_not_found_error
        - undefined_endpoint
        - store_id_not_found
        - unimplemented
      type: string
    UnprocessableContentErrorCode:
      default: no_throttled_error_code
      enum:
        - no_throttled_error_code
        - throttled_timeout_error
      type: string
    InternalErrorCode:
      default: no_internal_error
      enum:
        - no_internal_error
        - internal_error
        - deadline_exceeded
        - already_exists
        - resource_exhausted
        - failed_precondition
        - aborted
        - out_of_range
        - unavailable
        - data_loss
      type: string
    TupleKey:
      properties:
        condition:
          $ref: '#/components/schemas/RelationshipCondition'
        object:
          example: document:2021-budget
          maxLength: 256
          type: string
        relation:
          example: reader
          maxLength: 50
          type: string
        user:
          example: user:anne
          maxLength: 512
          type: string
      required:
        - user
        - relation
        - object
      type: object
    RelationshipCondition:
      properties:
        context:
          description: >-
            Additional context/data to persist along with the condition.

            The keys must match the parameters defined by the condition, and the
            value types must

            match the parameter type definitions.
          type: object
        name:
          description: >-
            A reference (by name) of the relationship condition defined in the
            authorization model.
          example: condition1
          maxLength: 256
          type: string
      required:
        - name
      type: object

````