## 1. Project Overview & Quickstart (ory/keto)

## File: README.md

<h1 align="center">
  
</h1>

<h4 align="center">
  [Chat](https://www.ory.com/chat) ·
  [Discussions](https://github.com/ory/keto/discussions) ·
  [Newsletter](https://www.ory.com/l/sign-up-newsletter) ·
  [Docs](https://www.ory.com/docs/) ·
  [Try Ory Network](https://console.ory.sh/) ·
  [Jobs](https://www.ory.com/jobs/)
</h4>

Ory Keto is the first and most popular open source implementation of "Zanzibar:
Google's Consistent, Global Authorization System". It provides a scalable,
performant authorization server for managing permissions at scale.

---




- [What is Ory Keto?](#what-is-ory-keto)
  - [Why Ory Keto](#why-ory-keto)
- [Deployment options](#deployment-options)
  - [Use Ory Keto on the Ory Network](#use-ory-keto-on-the-ory-network)
  - [Self-host Ory Keto](#self-host-ory-keto)
- [Quickstart](#quickstart)
- [Who is using Ory Keto](#who-is-using-ory-keto)
- [Ecosystem](#ecosystem)
  - [Ory Kratos: Identity and User Infrastructure and Management](#ory-kratos-identity-and-user-infrastructure-and-management)
  - [Ory Hydra: OAuth2 & OpenID Connect Server](#ory-hydra-oauth2--openid-connect-server)
  - [Ory Oathkeeper: Identity & Access Proxy](#ory-oathkeeper-identity--access-proxy)
  - [Ory Keto: Access Control Policies as a Server](#ory-keto-access-control-policies-as-a-server)
- [Documentation](#documentation)
- [Developing Ory Keto](#developing-ory-keto)
- [Security](#security)
  - [Disclosing vulnerabilities](#disclosing-vulnerabilities)
- [Telemetry](#telemetry)



## What is Ory Keto?

Ory Keto is an open source implementation of "Zanzibar: Google's Consistent,
Global Authorization System". It follows
[cloud architecture best practices](https://www.ory.com/docs/ecosystem/software-architecture-philosophy)
and focuses on:

- Scalable permission checks based on the Zanzibar model
- The Ory Permission Language for defining access control policies
- Relationship-based access control (ReBAC)
- Low latency permission checks (sub-10ms)
- Horizontal scaling to billions of relationships
- Consistency and high availability

We recommend starting with the
[Ory Keto introduction docs](https://www.ory.com/docs/keto) to learn more about
its architecture, feature set, and how it compares to other systems.

### Why Ory Keto

Ory Keto is designed to:

- Implement Google's Zanzibar authorization model at scale
- Provide low-latency permission checks for billions of relationships
- Support the Ory Permission Language for flexible access control
- Work with any identity provider through integration points
- Scale horizontally without effort
- Fit into modern cloud native environments such as Kubernetes and managed
  platforms

## Deployment options

You can run Ory Keto in two main ways:

- As a managed service on the Ory Network
- As a self hosted service under your own control, with or without the Ory
  Enterprise License

### Use Ory Keto on the Ory Network

The [Ory Network](https://www.ory.com/cloud) is the fastest way to use Ory
services in production. **Ory Permissions** is powered by the open source Ory
Keto server and is API compatible.

The Ory Network provides:

- Low latency permission checks based on Google's Zanzibar model with built-in
  support for the Ory Permission Language
- Identity and credential management that scales to billions of users and
  devices
- Registration, login, and account management flows for passkeys, biometrics,
  social login, SSO, and multi factor authentication
- OAuth2 and OpenID Connect for single sign on, API access, and machine to
  machine authorization
- GDPR friendly storage with data locality and compliance in mind
- Web based Ory Console and Ory CLI for administration and operations
- Cloud native APIs compatible with the open source servers
- Fair, usage based [pricing](https://www.ory.com/pricing)

Sign up for a
[free developer account](https://console.ory.sh/registration?utm_source=github&utm_medium=banner&utm_campaign=keto-readme)
to get started.

### Self-host Ory Keto

You can run Ory Keto yourself for full control over infrastructure, deployment,
and customization.

The [install guide](https://www.ory.com/docs/keto/install) explains how to:

- Install Keto on Linux, macOS, Windows, and Docker
- Configure databases such as PostgreSQL, MySQL, and CockroachDB
- Deploy to Kubernetes and other orchestration systems
- Build Keto from source

This guide uses the open source distribution to get you started without license
requirements. It is a great fit for individuals, researchers, hackers, and
companies that want to experiment, prototype, or run unimportant workloads
without SLAs. You get the full core engine, and you are free to inspect, extend,
and build it from source.

If you run Keto as part of a business-critical system, you should use a
commercial agreement to reduce operational and security risk. The **Ory
Enterprise License (OEL)** layers on top of self-hosted Keto and provides:

- Additional enterprise features that are not available in the open source
  version
- Regular security releases, including CVE patches, with service level
  agreements
- Support for advanced scaling, multi-tenancy, and complex deployments
- Premium support options with SLAs, direct access to engineers, and onboarding
  help
- Access to a private Docker registry with frequent and vetted, up-to-date
  enterprise builds

For guaranteed CVE fixes, current enterprise builds, advanced features, and
support in production, you need a valid
[Ory Enterprise License](https://www.ory.com/ory-enterprise-license) and access
to the Ory Enterprise Docker registry. To learn more,
[contact the Ory team](https://www.ory.com/contact/).

## Quickstart

Install the [Ory CLI](https://www.ory.com/docs/guides/cli/installation) and
create a new project to try Ory Permissions.

```bash
# Install the Ory CLI if you do not have it yet:
bash <(curl https://raw.githubusercontent.com/ory/meta/master/install.sh) -b . ory
sudo mv ./ory /usr/local/bin/

# Sign in or sign up
ory auth

# Create a new project
ory create project --create-workspace "Ory Open Source" --name "GitHub Quickstart" --use-project
```

Create a namespace with the Ory Permission Language:

```bash
# Write a simple configuration with one namespace
echo "class Document implements Namespace {}" > config.ts

# Apply that configuration
ory patch opl -f file://./config.ts

# Create a relationship that grants tom access to a document
echo "Document:secret#read@tom" \
  | ory parse relation-tuples --format=json - \
  | ory create relation-tuples -

# List all relationships
ory list relation-tuples

# Check if tom can read the document
ory check permission Document:secret read tom
```

## Who is using Ory Keto



The Ory community stands on the shoulders of individuals, companies, and
maintainers. The Ory team thanks everyone involved - from submitting bug reports
and feature requests, to contributing patches and documentation. The Ory
community counts more than 50.000 members and is growing. The Ory stack protects
7.000.000.000+ API requests every day across thousands of companies. None of
this would have been possible without each and everyone of you!

The following list represents companies that have accompanied us along the way
and that have made outstanding contributions to our ecosystem. _If you think
that your company deserves a spot here, reach out to
[office@ory.com](mailto:office@ory.com) now_!



| Name | Logo | Website | Case Study |
| --- | --- | --- | --- |
| OpenAI |  | [openai.com](https://openai.com/) | [OpenAI Case Study](https://www.ory.com/case-studies/openai) |
| Fandom |  | [fandom.com](https://www.fandom.com/) | [Fandom Case Study](https://www.ory.com/case-studies/fandom) |
| Lumin |  | [luminpdf.com](https://www.luminpdf.com/) | [Lumin Case Study](https://www.ory.com/case-studies/lumin) |
| Sencrop |  | [sencrop.com](https://sencrop.com/) | [Sencrop Case Study](https://www.ory.com/case-studies/sencrop) |
| OSINT Industries |  | [osint.industries](https://www.osint.industries/) | [OSINT Industries Case Study](https://www.ory.com/case-studies/osint) |
| HGV |  | [hgv.it](https://www.hgv.it/) | [HGV Case Study](https://www.ory.com/case-studies/hgv) |
| Maxroll |  | [maxroll.gg](https://maxroll.gg/) | [Maxroll Case Study](https://www.ory.com/case-studies/maxroll) |
| Zezam |  | [zezam.io](https://www.zezam.io/) | [Zezam Case Study](https://www.ory.com/case-studies/zezam) |
| T.RowePrice |  | [troweprice.com](https://www.troweprice.com/) |  |
| Mistral |  | [mistral.ai](https://www.mistral.ai/) |  |
| Axel Springer |  | [axelspringer.com](https://www.axelspringer.com/) |  |
| Hemnet |  | [hemnet.se](https://www.hemnet.se/) |  |
| Cisco |  | [cisco.com](https://www.cisco.com/) |  |
| Presidencia de la República Dominicana |  | [presidencia.gob.do](https://www.presidencia.gob.do/) |  |
| Moonpig |  | [moonpig.com](https://www.moonpig.com/) |  |
| Booster |  | [choosebooster.com](https://www.choosebooster.com/) |  |
| Zaptec |  | [zaptec.com](https://www.zaptec.com/) |  |
| Klarna |  | [klarna.com](https://www.klarna.com/) |  |
| Raspberry PI Foundation |  | [raspberrypi.org](https://www.raspberrypi.org/) |  |
| Tulip |  | [tulip.com](https://tulip.com/) |  |
| Hootsuite |  | [hootsuite.com](https://hootsuite.com/) |  |
| Segment |  | [segment.com](https://segment.com/) |  |
| Arduino |  | [arduino.cc](https://www.arduino.cc/) |  |
| Sainsbury's |  | [sainsburys.co.uk](https://www.sainsburys.co.uk/) |  |
| Contraste |  | [contraste.com](https://www.contraste.com/en) |  |
| inMusic |  | [inmusicbrands.com](https://inmusicbrands.com/) |  |
| Buhta |  | [buhta.com](https://buhta.com/) |  |
| Amplitude |  | [amplitude.com](https://amplitude.com/) |  |
| [](https://tier4.jp/en/) | [](https://kyma-project.io) | [](https://serlo.org/) | [](https://padis.io/) |
| [](https://cloudbear.eu/) | [](https://securityonionsolutions.com/) | [](https://factlylabs.com/) | [](https://cashdeck.com.au/) |
| [](https://nortal.com/) | [](https://www.ordermygear.com/) | [](https://r2devops.io/) | [](https://www.paralus.io/) |
| [](https://dyrector.io/) | [](https://pinniped.dev/) | [](https://pvotal.tech/) |  |



Many thanks to all individual contributors

[](https://opencollective.com/ory)



## Ecosystem



We build Ory on several guiding principles when it comes to our architecture
design:

- Minimal dependencies
- Runs everywhere
- Scales without effort
- Minimize room for human and network errors

Ory's architecture is designed to run best on a Container Orchestration system
such as Kubernetes, CloudFoundry, OpenShift, and similar projects. Binaries are
small (5-15MB) and available for all popular processor types (ARM, AMD64, i386)
and operating systems (FreeBSD, Linux, macOS, Windows) without system
dependencies (Java, Node, Ruby, libxml, ...).

### Ory Kratos: Identity and User Infrastructure and Management

[Ory Kratos](https://github.com/ory/kratos) is an API-first Identity and User
Management system that is built according to
[cloud architecture best practices](https://www.ory.com/docs/next/ecosystem/software-architecture-philosophy).
It implements core use cases that almost every software application needs to
deal with: Self-service Login and Registration, Multi-Factor Authentication
(MFA/2FA), Account Recovery and Verification, Profile, and Account Management.

### Ory Hydra: OAuth2 & OpenID Connect Server

[Ory Hydra](https://github.com/ory/hydra) is an OpenID Certified™ OAuth2 and
OpenID Connect Provider which easily connects to any existing identity system by
writing a tiny "bridge" application. It gives absolute control over the user
interface and user experience flows.

### Ory Oathkeeper: Identity & Access Proxy

[Ory Oathkeeper](https://github.com/ory/oathkeeper) is a BeyondCorp/Zero Trust
Identity & Access Proxy (IAP) with configurable authentication, authorization,
and request mutation rules for your web services: Authenticate JWT, Access
Tokens, API Keys, mTLS; Check if the contained subject is allowed to perform the
request; Encode resulting content into custom headers (`X-User-ID`), JSON Web
Tokens and more!

### Ory Keto: Access Control Policies as a Server

[Ory Keto](https://github.com/ory/keto) is a policy decision point. It uses a
set of access control policies, similar to AWS IAM Policies, in order to
determine whether a subject (user, application, service, car, ...) is authorized
to perform a certain action on a resource.



## Documentation

The full Ory Keto documentation is available at
[www.ory.com/docs/keto](https://www.ory.com/docs/keto), including:

- [Installation guides](https://www.ory.com/docs/keto/install)
- [Configuration reference](https://www.ory.com/docs/keto/reference/configuration)
- [HTTP API documentation](https://www.ory.com/docs/keto/sdk/api)
- [Ory Permission Language guide](https://www.ory.com/docs/keto/modeling/create-permission-model)

For upgrading and changelogs, check [UPGRADE.md](./UPGRADE.md) and
[CHANGELOG.md](./CHANGELOG.md).

## Developing Ory Keto

See [DEVELOP.md](./DEVELOP.md) for information on:

- Contribution guidelines
- Prerequisites
- Install from source
- Running tests
- Build Docker image

## Security

### Disclosing vulnerabilities

If you think you found a security vulnerability, please refrain from posting it
publicly on the forums, the chat, or GitHub. You can find all info for
responsible disclosure in our
[security.txt](https://www.ory.com/.well-known/security.txt).

## Telemetry

Our services collect summarized, anonymized data that can optionally be turned
off. Click [here](https://www.ory.com/docs/ecosystem/sqa) to learn more.

---

## File: docs/ory_permission_language_spec.md

# The "Ory Permission Language" Specification

Enforcing fine-grained permissions is a critical building block of mature
technology solutions that protect privacy and identity in the information age.
Several proprietary languages to represent permission already exist, namely the
[Authzed Schema Language](https://docs.authzed.com/reference/schema-lang) and
[Auth0 FGA](https://docs.fga.dev/). Most permissions are defined by normal
developers who typically are most familiar with Web technologies like JavaScript
or Typescript. We see the need for a developer-friendly configuration language
for permissions that has such a small learning curve that most developers can
understand and use it with close to no effort. We therefore chose to define our
permissions configuration language as a subset of the most common
general-purpose programming language: JavaScript/TypeScript.

The Ory Permission Language is a syntactical subset of TypeScript. Along with
type definitions for the syntax elements of the language (such as `Namespace` or
`Context`), users can get context help from their IDE while writing the
configuration.

## Notation

The syntax is specified using the Extended Backus-Naur Form (EBNF):

```ebnf
Production  = production_name "=" [ Expression ] "." .
Expression  = Alternative { "|" Alternative } .
Alternative = Term { Term } .
Term        = production_name | token [ "…" token ] | Group | Option | Repetition .
Group       = "(" Expression ")" .
Option      = "[" Expression "]" .
Repetition  = "{" Expression "}" .
```

Productions are expressions constructed from terms and the following operators,
in increasing precedence:

```ebnf
|   alternation
()  grouping
[]  option (0 or 1 times)
{}  repetition (0 to n times)
```

Lower-case production names are used to identify lexical tokens. Non-terminals
are in CamelCase. Lexical tokens are enclosed in double quotes `""` or single
quotes `''`.

The form `a … b` represents the set of characters from a through b as
alternatives. The horizontal ellipsis `…` is also used elsewhere in the spec to
informally denote various enumerations or code snippets that are not further
specified.

## Configuraton text representation

The configuration is encoded in UTF-8.

## Lexical elements

### Comments

1. Line comments start with the character sequence `//` and stop at the end of
   the line.
2. General comments start with the character sequence `/*` and stop with the
   first subsequent character sequence `*/`.
3. Documentation comments start with the character sequence `/**` and stop with
   the first subsequent character sequence `*/`.

### Identifiers

Identifiers name program entities such as variables and types. An identifier is
a sequence of one or more letters and digits. The first character in an
identifier must be a letter.

```ebnf
identifier = letter { letter | digit } .
digit      = "0" … "9" .
letter     = "A" … "Z" | "a" … "z" | "_" .
```

### String literals

String literals represent string constants as sequences of characters.

```ebnf
string_lit    = single_quoted | double_quoted .
single_quoted = "'" identifier "'" .
double_quoted = '"' identifier '"' .
```

### Keywords

The configuration language has the following keywords:

- `class`
- `implements`
- `related`
- `permits`
- `this`
- `ctx`
- `id`
- `imports`
- `exports`
- `as`

### Builtin Types

The following types are built in:

- `Context`
- `Namespace`
- `Namespace[]`
- `boolean`
- `string`
- `SubjectSet<T, R>`

In TypeScript, they would be defined as follows:

```typescript
type Context = { subject: never }

interface Namespace {
  related?: { [relation: string]: Namespace[] }
  permits?: { [method: string]: (ctx: Context) => boolean }
}

interface Array<Namespace> {
  includes(element: Namespace): boolean
  traverse(iteratorfn: (element: Namespace) => boolean): boolean
}

type SubjectSet<A extends Namespace, R extends keyof A["related"]> =
  A["related"][R] extends Array ? T : never
```

### Operators

The following character sequences represent boolean operators:

| Operator | Signature      | Semantic                             |
| -------- | -------------- | ------------------------------------ |
| `&&`     | _x_ `&&` _y_   | true iff. both _x_ and _y_ are true  |
| `\|\|`   | _x_ `\|\|` _y_ | true iff. either _x_ or _y_ are true |
| `!`      | `!` _x_        | true iff. _x_ is false               |

The following character sequences represent miscellaneous operators:

| Operator | Example                                  | Semantic                                                          |
| -------- | ---------------------------------------- | ----------------------------------------------------------------- |
| `(`, `)` | `x()`                                    | call function `x`                                                 |
| `[]`     | `T[]`                                    | `T` is an array type                                              |
| `<`, `>` | `SubjectSet<Group, "members">`           | Type reference to the "members" relation of the "Group" namespace |
| `{`, `}` | `class x {}`                             | Scope delimiters                                                  |
| `=>`     | `list.transitive(el => f(el))`           | Lambda definition token.                                          |
| `.`      | `this.x`                                 | Property traversal token                                          |
| `:`      | `relation: type`                         | Relation/type separator token                                     |
| `=`      | `permits = {...}`                        | Assignment token                                                  |
| `,`      | `{x: 1, y: 2}`                           | Property separator                                                |
| `'`      | `'string'`                               | Single quoted string literal                                      |
| `"`      | `"string"`                               | Double quoted string literal                                      |
| `*`      | `import * from @ory/permission-language` | Import glob                                                       |
| `\|`     | `(User \| Group)[]`                      | Type union                                                        |

## Statements

### Type declaration

The top level of the configuration consists of a list of `class` declarations
for each namespace. Each `class` consists of relation declarations and
permission declarations.

```ebnf
Config          = [ ClassDecl ] .
ClassDecl       = "class" identifier "implements" "Namespace" "{" ClassSpec "}" .
ClassSpec       = [ RelationDecls ] | [ PermissionDefns] .
```

The following example declares the type _User_.

```ts
class User implements Namespace {}
```

### Relation declaration

The `related` section of type declarations defines relations. Unlike regular
TypeScript, `RelationName` must be a unique identifier used as the relation
strings in the tuples. The `TypeName` must be the name of another `type` that is
defined above or below (in TypeScript: a class that implements `Namespace`).

Type unions (`|`) can be used to denote that a relation can have subjects of
multiple types, e.g., `viewers: (User | SubjectSet<Group, "members">)[]`,
meaning that the subject of the "viewer" relation can be either a "User", or a
subject set "Group#members".

```ebnf
RelationDecls   = "related" "=" "{" { RelationName ":" ArrayType } "}" .
RelationName    = identifier .
ArrayType       = RelationType | ( "(" RelationType { "|" RelationType } ")" ) "[]" .
RelationType    = SubjectType | SubjectSetType .
SubjectType     = TypeName .
SubjectSetType  = "SubjectSet" "<" TypeName, string_lit ">" .
TypeName        = identifier .
```

Note that all relations are defined as array types `T[]` because there are
naturally only many-to-many relations in Keto.

The following declares a type _Document_ with three relations: _owners_ and
_viewers_, both of which have _users_ as subjects. Additionally, the relation
_parent_ has type _Document_.

```ts
class User {}

class Document {
  related = {
    parents: Document[]
    owners: User[]
    viewers: User[]
  }
}
```

### Permission definition

Permissions are defined as functions within class declarations that take a
parameter `ctx` of type `Context` and evaluate to a boolean `true` or `false`.

The type annotations for `ctx` and the return value are optional.

```ebnf
PermissionDefns = "permits" "=" "{" Permission [ "," Permission ] "}" .
Permission      = PermissionSign "=>" PermissionBody .
PermissionSign  = PermissionName ":" "(" "ctx" [ ":" "Context" ] ")" [ ":" "boolean" ] .
PermissionName  = identifier .
```

The `ctx` object is a fixed parameter that contains the `subject` for which the
permission check should be conducted:

```ts
ctx = { subject: "some_user_id" }
```

The context will contain more fields in the future, e.g., the IP range or
geolocation, the time of day, or the security level of the device making the
request.

```ebnf
PermissionBody  = ( "(" PermissionBody ")" ) | ( "!" PermissionBody ) | ( PermissionCheck | { Operator PermissionBody } ) .
Operator        = "||" | "&&" .
PermissionCheck = TransitiveCheck | IncludesCheck .
```

The body of a permission check is either one of:

- a `IncludesCheck`, a check that something is in a set, e.g.,
  `this.related.viewers.includes(ctx.subject)`:

  ```ebnf
  IncludesCheck = Var "." "related" "." RelationName "." "includes" "(" "ctx" "." "subject" ")" .
  Var           = identifier .
  ```

- a `TranstitiveCheck`, a call to a permission on a relation, e.g.,
  `this.related.parents.transitive(p => p.permits.view(ctx))`:

  ```ebnf
  TransitiveCheck = "this" "." "related" "." RelationName "." "transitive" "(" Var "=>" ( PermissionCall | IncludesCheck ) ")" .
  PermissionCall  = Var "." "permits" "." PermissionName "(" "ctx" ")" .
  ```

## Implementation notes

`IncludeCheck` and `TransitiveCheck` translate to Zanzibar concepts as follows:

| Keto Config                                               | Zanzibar AST                                                                         |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `this.related.R.includes(ctx.subject)`                    | `computed_userset { relation: "R" } }`                                               |
| `this.related.R.transitive(x = x.permits.P(ctx.subject))` | `tuple_to_userset { tupleset { relation: "R" } computed_userset { relation: "P" } }` |

## Type checking

The following type checks are performed once the config is fully parsed:

- Given a `TypeName` as `X` (e.g., in `RelationDecls`), we check that there
  exists a class declaration for `X`.
- Given a `SubjectSetType` as `SubjectSet<T, R>`, we check that `R` is a
  relation defined for `T`.
- Given an `IncludesCheck` as `this.related.R.includes(ctx.subject)`, we check
  that
  - `R` is a relation defined for the current namespace.
- Given a `TransitiveCheck` as
  `this.related.R.transitive(x = x.permits.P(ctx.subject))`, we check that
  - `R` is a relation defined for the current namespace and that
  - `P` is a permission defined for all types referenced by `R`.
- Given a `TransitiveCheck` as
  `this.related.R.transitive(x = x.related.S.includes(ctx.subject))`, we check
  that
  - `R` is a relation defined for the current namespace and that
  - `S` is a relation defined for all types referenced by `R`.

## Examples

The config can be type-checked in `strict` mode by TypeScript with the
[noLib](https://www.typescriptlang.org/tsconfig#noLib) option (preventing the
standard globals), and the
[strictPropertyInitialization](https://www.typescriptlang.org/tsconfig#strictPropertyInitialization)
option (allowing uninitialized properties).

```ts
class User implements Namespace {
  related: {
    manager: User[]
  }
}

class Group implements Namespace {
  related: {
    members: (User | Group)[]
  }
}

class Folder implements Namespace {
  related: {
    parents: File[]
    viewers: (User | SubjectSet<Group, "members">)[]
  }

  permits = {
    view: (ctx: Context): boolean => this.related.viewers.includes(ctx.subject),
  }
}

class File implements Namespace {
  related: {
    parents: (File | Folder)[]
    viewers: (User | SubjectSet<Group, "members">)[]
    owners: (User | SubjectSet<Group, "members">)[]
    siblings: File[]
  }

  permits = {
    view: (ctx: Context): boolean =>
      this.related.parents.traverse((p) =>
        p.related.viewers.includes(ctx.subject),
      ) ||
      this.related.parents.traverse((p) => p.permits.view(ctx)) ||
      this.related.viewers.includes(ctx.subject) ||
      this.related.owners.includes(ctx.subject),

    edit: (ctx: Context) => this.related.owners.includes(ctx.subject),

    rename: (ctx: Context) =>
      this.related.siblings.traverse((s) => s.permits.edit(ctx)),
  }
}
```

---

## File: docs/README.md

# Documentation

Please find the documentation at
[www.ory.com/docs/keto](https://www.ory.com/docs/keto).

To contribute to the documentation, please head over to:
[github.com/ory/docs/tree/master/docs/keto](https://github.com/ory/docs/tree/master/docs/keto)

---

## File: internal/persistence/sql/migrations/templates/README.md

# The fizz templates are frozen at this point. Add SQL migrations right in `./sql`

---

## File: internal/httpclient/docs/BatchCheckPermissionBody.md

# BatchCheckPermissionBody

## Properties

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Tuples** | Pointer to [**[]Relationship**](Relationship.md) |  | [optional] 

## Methods

### NewBatchCheckPermissionBody

`func NewBatchCheckPermissionBody() *BatchCheckPermissionBody`

NewBatchCheckPermissionBody instantiates a new BatchCheckPermissionBody object
This constructor will assign default values to properties that have it defined,
and makes sure properties required by API are set, but the set of arguments
will change when the set of required properties is changed

### NewBatchCheckPermissionBodyWithDefaults

`func NewBatchCheckPermissionBodyWithDefaults() *BatchCheckPermissionBody`

NewBatchCheckPermissionBodyWithDefaults instantiates a new BatchCheckPermissionBody object
This constructor will only assign default values to properties that have it defined,
but it doesn't guarantee that properties required by API are set

### GetTuples

`func (o *BatchCheckPermissionBody) GetTuples() []Relationship`

GetTuples returns the Tuples field if non-nil, zero value otherwise.

### GetTuplesOk

`func (o *BatchCheckPermissionBody) GetTuplesOk() (*[]Relationship, bool)`

GetTuplesOk returns a tuple with the Tuples field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### SetTuples

`func (o *BatchCheckPermissionBody) SetTuples(v []Relationship)`

SetTuples sets Tuples field to given value.

### HasTuples

`func (o *BatchCheckPermissionBody) HasTuples() bool`

HasTuples returns a boolean if a field has been set.


[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

---

## File: internal/httpclient/docs/BatchCheckPermissionResult.md

# BatchCheckPermissionResult

## Properties

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Results** | [**[]CheckPermissionResultWithError**](CheckPermissionResultWithError.md) | An array of check results. The order aligns with the input order. | 

## Methods

### NewBatchCheckPermissionResult

`func NewBatchCheckPermissionResult(results []CheckPermissionResultWithError, ) *BatchCheckPermissionResult`

NewBatchCheckPermissionResult instantiates a new BatchCheckPermissionResult object
This constructor will assign default values to properties that have it defined,
and makes sure properties required by API are set, but the set of arguments
will change when the set of required properties is changed

### NewBatchCheckPermissionResultWithDefaults

`func NewBatchCheckPermissionResultWithDefaults() *BatchCheckPermissionResult`

NewBatchCheckPermissionResultWithDefaults instantiates a new BatchCheckPermissionResult object
This constructor will only assign default values to properties that have it defined,
but it doesn't guarantee that properties required by API are set

### GetResults

`func (o *BatchCheckPermissionResult) GetResults() []CheckPermissionResultWithError`

GetResults returns the Results field if non-nil, zero value otherwise.

### GetResultsOk

`func (o *BatchCheckPermissionResult) GetResultsOk() (*[]CheckPermissionResultWithError, bool)`

GetResultsOk returns a tuple with the Results field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### SetResults

`func (o *BatchCheckPermissionResult) SetResults(v []CheckPermissionResultWithError)`

SetResults sets Results field to given value.



[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

---

## File: internal/httpclient/docs/CheckOplSyntaxResult.md

# CheckOplSyntaxResult

## Properties

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Errors** | Pointer to [**[]ParseError**](ParseError.md) | The list of syntax errors | [optional] 

## Methods

### NewCheckOplSyntaxResult

`func NewCheckOplSyntaxResult() *CheckOplSyntaxResult`

NewCheckOplSyntaxResult instantiates a new CheckOplSyntaxResult object
This constructor will assign default values to properties that have it defined,
and makes sure properties required by API are set, but the set of arguments
will change when the set of required properties is changed

### NewCheckOplSyntaxResultWithDefaults

`func NewCheckOplSyntaxResultWithDefaults() *CheckOplSyntaxResult`

NewCheckOplSyntaxResultWithDefaults instantiates a new CheckOplSyntaxResult object
This constructor will only assign default values to properties that have it defined,
but it doesn't guarantee that properties required by API are set

### GetErrors

`func (o *CheckOplSyntaxResult) GetErrors() []ParseError`

GetErrors returns the Errors field if non-nil, zero value otherwise.

### GetErrorsOk

`func (o *CheckOplSyntaxResult) GetErrorsOk() (*[]ParseError, bool)`

GetErrorsOk returns a tuple with the Errors field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### SetErrors

`func (o *CheckOplSyntaxResult) SetErrors(v []ParseError)`

SetErrors sets Errors field to given value.

### HasErrors

`func (o *CheckOplSyntaxResult) HasErrors() bool`

HasErrors returns a boolean if a field has been set.


[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

---

## File: internal/httpclient/docs/CheckPermissionResult.md

# CheckPermissionResult

## Properties

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Allowed** | **bool** | whether the relation tuple is allowed | 

## Methods

### NewCheckPermissionResult

`func NewCheckPermissionResult(allowed bool, ) *CheckPermissionResult`

NewCheckPermissionResult instantiates a new CheckPermissionResult object
This constructor will assign default values to properties that have it defined,
and makes sure properties required by API are set, but the set of arguments
will change when the set of required properties is changed

### NewCheckPermissionResultWithDefaults

`func NewCheckPermissionResultWithDefaults() *CheckPermissionResult`

NewCheckPermissionResultWithDefaults instantiates a new CheckPermissionResult object
This constructor will only assign default values to properties that have it defined,
but it doesn't guarantee that properties required by API are set

### GetAllowed

`func (o *CheckPermissionResult) GetAllowed() bool`

GetAllowed returns the Allowed field if non-nil, zero value otherwise.

### GetAllowedOk

`func (o *CheckPermissionResult) GetAllowedOk() (*bool, bool)`

GetAllowedOk returns a tuple with the Allowed field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### SetAllowed

`func (o *CheckPermissionResult) SetAllowed(v bool)`

SetAllowed sets Allowed field to given value.



[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

---

## File: internal/httpclient/docs/CheckPermissionResultWithError.md

# CheckPermissionResultWithError

## Properties

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Allowed** | **bool** | whether the relation tuple is allowed | 
**Error** | Pointer to **string** | any error generated while checking the relation tuple | [optional] 

## Methods

### NewCheckPermissionResultWithError

`func NewCheckPermissionResultWithError(allowed bool, ) *CheckPermissionResultWithError`

NewCheckPermissionResultWithError instantiates a new CheckPermissionResultWithError object
This constructor will assign default values to properties that have it defined,
and makes sure properties required by API are set, but the set of arguments
will change when the set of required properties is changed

### NewCheckPermissionResultWithErrorWithDefaults

`func NewCheckPermissionResultWithErrorWithDefaults() *CheckPermissionResultWithError`

NewCheckPermissionResultWithErrorWithDefaults instantiates a new CheckPermissionResultWithError object
This constructor will only assign default values to properties that have it defined,
but it doesn't guarantee that properties required by API are set

### GetAllowed

`func (o *CheckPermissionResultWithError) GetAllowed() bool`

GetAllowed returns the Allowed field if non-nil, zero value otherwise.

### GetAllowedOk

`func (o *CheckPermissionResultWithError) GetAllowedOk() (*bool, bool)`

GetAllowedOk returns a tuple with the Allowed field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### SetAllowed

`func (o *CheckPermissionResultWithError) SetAllowed(v bool)`

SetAllowed sets Allowed field to given value.


### GetError

`func (o *CheckPermissionResultWithError) GetError() string`

GetError returns the Error field if non-nil, zero value otherwise.

### GetErrorOk

`func (o *CheckPermissionResultWithError) GetErrorOk() (*string, bool)`

GetErrorOk returns a tuple with the Error field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### SetError

`func (o *CheckPermissionResultWithError) SetError(v string)`

SetError sets Error field to given value.

### HasError

`func (o *CheckPermissionResultWithError) HasError() bool`

HasError returns a boolean if a field has been set.


[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

---

## File: internal/httpclient/docs/CreateRelationshipBody.md

# CreateRelationshipBody

## Properties

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Namespace** | Pointer to **string** | Namespace to query | [optional] 
**Object** | Pointer to **string** | Object to query | [optional] 
**Relation** | Pointer to **string** | Relation to query | [optional] 
**SubjectId** | Pointer to **string** | SubjectID to query  Either SubjectSet or SubjectID can be provided. | [optional] 
**SubjectSet** | Pointer to [**SubjectSet**](SubjectSet.md) |  | [optional] 

## Methods

### NewCreateRelationshipBody

`func NewCreateRelationshipBody() *CreateRelationshipBody`

NewCreateRelationshipBody instantiates a new CreateRelationshipBody object
This constructor will assign default values to properties that have it defined,
and makes sure properties required by API are set, but the set of arguments
will change when the set of required properties is changed

### NewCreateRelationshipBodyWithDefaults

`func NewCreateRelationshipBodyWithDefaults() *CreateRelationshipBody`

NewCreateRelationshipBodyWithDefaults instantiates a new CreateRelationshipBody object
This constructor will only assign default values to properties that have it defined,
but it doesn't guarantee that properties required by API are set

### GetNamespace

`func (o *CreateRelationshipBody) GetNamespace() string`

GetNamespace returns the Namespace field if non-nil, zero value otherwise.

### GetNamespaceOk

`func (o *CreateRelationshipBody) GetNamespaceOk() (*string, bool)`

GetNamespaceOk returns a tuple with the Namespace field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### SetNamespace

`func (o *CreateRelationshipBody) SetNamespace(v string)`

SetNamespace sets Namespace field to given value.

### HasNamespace

`func (o *CreateRelationshipBody) HasNamespace() bool`

HasNamespace returns a boolean if a field has been set.

### GetObject

`func (o *CreateRelationshipBody) GetObject() string`

GetObject returns the Object field if non-nil, zero value otherwise.

### GetObjectOk

`func (o *CreateRelationshipBody) GetObjectOk() (*string, bool)`

GetObjectOk returns a tuple with the Object field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### SetObject

`func (o *CreateRelationshipBody) SetObject(v string)`

SetObject sets Object field to given value.

### HasObject

`func (o *CreateRelationshipBody) HasObject() bool`

HasObject returns a boolean if a field has been set.

### GetRelation

`func (o *CreateRelationshipBody) GetRelation() string`

GetRelation returns the Relation field if non-nil, zero value otherwise.

### GetRelationOk

`func (o *CreateRelationshipBody) GetRelationOk() (*string, bool)`

GetRelationOk returns a tuple with the Relation field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### SetRelation

`func (o *CreateRelationshipBody) SetRelation(v string)`

SetRelation sets Relation field to given value.

### HasRelation

`func (o *CreateRelationshipBody) HasRelation() bool`

HasRelation returns a boolean if a field has been set.

### GetSubjectId

`func (o *CreateRelationshipBody) GetSubjectId() string`

GetSubjectId returns the SubjectId field if non-nil, zero value otherwise.

### GetSubjectIdOk

`func (o *CreateRelationshipBody) GetSubjectIdOk() (*string, bool)`

GetSubjectIdOk returns a tuple with the SubjectId field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### SetSubjectId

`func (o *CreateRelationshipBody) SetSubjectId(v string)`

SetSubjectId sets SubjectId field to given value.

### HasSubjectId

`func (o *CreateRelationshipBody) HasSubjectId() bool`

HasSubjectId returns a boolean if a field has been set.

### GetSubjectSet

`func (o *CreateRelationshipBody) GetSubjectSet() SubjectSet`

GetSubjectSet returns the SubjectSet field if non-nil, zero value otherwise.

### GetSubjectSetOk

`func (o *CreateRelationshipBody) GetSubjectSetOk() (*SubjectSet, bool)`

GetSubjectSetOk returns a tuple with the SubjectSet field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.

### SetSubjectSet

`func (o *CreateRelationshipBody) SetSubjectSet(v SubjectSet)`

SetSubjectSet sets SubjectSet field to given value.

### HasSubjectSet

`func (o *CreateRelationshipBody) HasSubjectSet() bool`

HasSubjectSet returns a boolean if a field has been set.


[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

## 2. Official Technical Reference & Guides (ory/docs)

<h1 align="center">Ory Documentation</h1>

<h4 align="center">
    [Chat](https://slack.ory.com) |
    [Newsletter](https://www.ory.com/l/sign-up-newsletter)
    [Documentation](https://www.ory.com/docs/) |
    [Support this project!](https://opencollective.com/ory)
    [Work in Open Source, Ory is hiring!](https://www.ory.com/jobs/)
</h4>




- [Overview](#overview)
- [Style guide](#style-guide)
  - [Grammar and style](#grammar-and-style)
    - [Lists](#lists)
    - [Headings](#headings)
  - [Formatting](#formatting)
    - [Document front matter](#document-front-matter)
    - [Bolding, 'code formatting'](#bolding-code-formatting)
    - [Linking](#linking)
    - [Code blocks](#code-blocks)
    - [Placeholders and dummy data](#placeholders-and-dummy-data)
    - [UI references](#ui-references)
    - [Diagrams](#diagrams)
  - [Import & reference content](#import--reference-content)
    - [Markdown partials](#markdown-partials)
    - [Code snippets](#code-snippets)
      - [From GitHub](#from-github)
      - [From this repository](#from-this-repository)
  - [Screenshots and videos](#screenshots-and-videos)
    - [Compressing images](#compressing-images)
    - [Recording and compressing videos](#recording-and-compressing-videos)
  - [Ory Console](#ory-console)
    - [Navigate to Ory Console Pages](#navigate-to-ory-console-pages)
  - [Testing](#testing)
    - [Redirects](#redirects)
      - [How to add a redirect](#how-to-add-a-redirect)
  - [Formatting documentation](#formatting-documentation)
  - [Adding content to "Examples" page](#adding-content-to-examples-page)
  - [CLI and API reference - auto-generated content](#cli-and-api-reference---auto-generated-content)



# Overview

Ory documentation is the single source of truth for usage, implementation,
configuration, and troubleshooting of the Ory Network and all projects of the
[Ory Ecosystem](https://www.ory.com/docs/ecosystem/projects/). The documentation
is best consumed through the
[Ory documentation portal](https://www.ory.com/docs/).

To see the source code of each of the projects, visit the project repository:

- [Ory Kratos](https://github.com/ory/kratos/)
- [Ory Hydra](https://github.com/ory/hydra/)
- [Ory Oathkeeper](https://github.com/ory/oathkeeper/)
- [Ory Keto](https://github.com/ory/keto/)

Documentation of other Ory projects:

- [Ory Kubernetes Helm Charts](https://github.com/ory/k8s/tree/master/docs/helm)
- [Ory Dockertest](https://github.com/ory/dockertest/blob/v3/README.md)
- [Ory SDKs](https://github.com/ory/sdk/blob/master/README.md)

# Style guide

This style guide outlines the most important rules and conventions that apply to
the Ory documentation. If there are no Ory-specific requirements or guidelines
for a given topic, refer to the
[Microsoft Writing Style Guide](https://learn.microsoft.com/en-us/style-guide/welcome/)
and follow the rules described there.

## Grammar and style

Ory documentation must be clear, concise, and unambiguous. To achieve that,
follow these simple rules:

1. Use active voice and present tense.
2. Always write in American English.
3. Use
   [zero conditional](https://www.ef.com/wwen/english-resources/english-grammar/zero-conditional/)
   when talking about the cause-and-effect in software behavior.
4. Use the right words to make sure that your message is clear and unambiguous.
   Don't use words like "should", "could", or "may".
5. Don't use phrasal verbs, colloquialisms, and jargon.
6. Don't refer to users in ways that imply their sex.
7. Don't use contractions of Latin origins such as `e.g` or `i.e`.
8. Remember to use articles (`a`, `an`, `the`) in your writing.
9. Use common contractions such as `aren't`, `don't`, `doesn't` to sound
   friendly and informal.

### Lists

Ory follows the
[Microsoft Writing Style Guide list formatting guidelines](https://learn.microsoft.com/en-us/style-guide/scannable-content/lists).

- List items must begin with a capital letter unless there's a specific reason
  not to do that. For example, the item is a proper name that's not capitalized,
  a parameter, or a command wrapped in backticks (`` ` ``).
- Don't use punctuation such as commas (`,`), semicolons (`;`), or conjunctions
  (`and`, `or`) at the end of list items.
- Use periods (`.`) only at the end of list items that are proper sentences,
  even very short ones.
- Make list items consistent in structure. For example, if one list item is a
  full sentence, make all list items full sentences. Don't use different
  structures for list items in a single list.
- Indent lines with 3 spaces to denote nested sub-items in lists. Indent text,
  code blocks, and images.
- When a bulleted list presents parallel items that each pair a label with an
  explanation, bold the label as a lead-in, followed by an em dash and the
  explanation. Use this pattern only when every bullet shares it. For example:
  - **Fully managed infrastructure** — Ory Network runs a global edge network
    with multi-region availability, automatic scaling, and high availability.
    You don't patch servers, rotate keys, or manage failover.
  - **Predictable pricing** — Usage-based billing with no per-seat fees, so cost
    scales with traffic rather than team size.

### Headings

- Use
  [sentence case](https://docs.microsoft.com/en-us/style-guide/text-formatting/using-type/use-sentence-style-capitalization)
  for headings.
- The highest heading level in documents is `h2`. Use `h1` only when you
  override the document `title`.
- The lowest heading level in documents is `h4`. If you absolutely need to add
  more heading levels, don't go lower than `h5`.
- Avoid using symbols and special characters in headings.
- Leave one blank line before and after a heading.
- Don't use links in headings.
- Headings play an important role in SEO and searchability and make the document
  more scannable. Make your headings short and true to the content they
  introduce.

## Formatting

Write in [Markdown](https://www.markdownguide.org/). Don't mix HTML tags with
Markdown. Files with the `.mdx` extension use
[JSX-extended Markdown (MDX)](https://mdxjs.com/).

### Document front matter

Add this front matter to every document you create:

```md
---
id: excellent_feature
title: Learn how to use the excellent feature in your implementation
sidebar_label: Excellent feature
slug: excellent-feature-for-some-reason
---
```

- `id` is the document identifier that makes up the last part of the document
  URL. Try to come up with a short ID that accurately describes the content. IDs
  that use multiple words must use hyphens (`-`) to separate the words.
- `title` is the document title that’s displayed as the page header. Used by
  search engines when displaying search results. Try to make it descriptive so
  that it helps readers understand what the document is about at the first
  glance. If it comes out long(ish), you can overwrite it by adding a `h1` in
  the very first line following the front matter. Use sentence case.
- `sidebar_label` represents the document title used in the sidebar (left
  navigation). Create a short document title that fits the sidebar width. Use
  sentence case.
- `slug` is an optional property that allows you to customize the document URL.
  Use it to create more meaningful, SEO-friendly URLs.
- `description` is a one-sentence summary of the page. Any document that appears
  as a card in a sidebar category (a generated category index) must set it,
  because Docusaurus derives the card text from `createExcerpt`, which only
  keeps the first physical line of the first paragraph and truncates at the
  source line wrap. Setting `description` gives you the full, intended card text
  and is also used by search engines. Keep it to one short sentence.

### Bolding, 'code formatting'

- Use only `code` and **bold** formatting. Don't use any other formatting.
- For inline code, wrap text in single backticks (`` ` ``). For code blocks use
  three backticks (` ``` `)
- Use `code` formatting for:
  - Commands, for example `ory --help`
  - File names and paths, for example `file.txt`, `~/Desktop/git/docs`
  - Environment variables, for example `CUSTOM_ENV_VAR`
- Use **bold** only when writing about user interface (UI) elements.

### Linking

- Link to external web pages using absolute links. Don't expose the link on its
  own. Instead, embed it in descriptive text. For example:

  ```
  Ory documentation uses [Prism syntax highlighting](https://prismjs.com/).
  ```

- Link to documents within this repository using relative links. When
  referencing the file, use the file name.

  ```
  [Some link](../path/to/file.mdx)
  ```

### Code blocks

- Always add a programming language identifier to code blocks. Ory documentation
  uses [Prism syntax highlighting](https://prismjs.com/).

  ````
  ```json
  {some-JSON-code-here}
  ```
  ````

- For command line examples, use `shell` as the programming language identifier.
  Don't put `$` before the command.

  ````
  ```shell
  ory get identities
  ```
  ````

- For Ory Permissions (Keto) relation tuples, use `keto-relation-tuples`
  language identifier, and for relationships use `keto-relationships`.

  ````
  ```keto-relation-tuples
  namespace:object#relation:subject
  // comment
  ```

  ```keto-relationships
  namespace:subject is relation of object
  is namespace:subject allowed to permission on object?
  // comment
  ```
  ````

- For multi-line commands, indent subsequent lines of the command with two
  spaces.

  ````
  ```shell
  curl --request GET -sL \
    --header "Content-Type: application/json" \
    --header "Authorization: Bearer {ORY_API_KEY}" \
    'https://{project-slug}.projects.oryapis.com/admin/identities/{identity_id}?include_credential=oidc'
  ```
  ````

### Placeholders and dummy data

Using placeholders and dummy data in code snippets and command examples is a
good way to ensure that users run commands in the context of their setups and,
as a result, achieve success faster. Additionally, this fabricated information
prevents leaking of sensitive data such as tokens or API keys.

Follow these rules when using placeholders and dummy data:

- Introduce placeholders and dummy data in curly brackets with a preceding $ so
  they can be used in bash commands.
- Use colons (`-`) or underscores (`_`) to separate multiple words, for example
  `{ORY_SESSION_COOKIE}` or `{project-slug}`.
- When referring to a project API URL or SDK URL, always use
  `https://$PROJECT_SLUG.projects.oryapis.com`.
- When referring to scenarios in which the user runs a custom domain, use
  `https://ory.your-custom-domain.com`.
- Always use short, but descriptive, verbal placeholders. Don't mix digits and
  letters to mimic the format of the data you mock.

### UI references

When talking about any user interface (UI) in the Ory documentation, follow
these rules:

- When referring to UI elements, always use the exact text associated with the
  given element.
- Format the name of the UI element you refer to in **bold**.
- Format any user input with `code`.

> Example: In the **Identity Model Schema** box, type `MyCustomIdentitySchema`.

### Diagrams

Use [Mermaid](https://mermaid-js.github.io/mermaid/#/) to create diagrams. You
can run the tool locally or use [Mermaid Live Editor](https://mermaid.live) in
the browser. See the
[Mermaid Cheatsheet](https://jojozhuang.github.io/tutorial/mermaid-cheat-sheet/)
for a detailed description on how to use Mermaid.

To add a Mermaid diagram, use this `mdx-code-block`:

````md
```mdx-code-block
import Mermaid from "@site/src/theme/Mermaid"
<Mermaid
  chart={`

{your-Mermaid-code}

`}
/>
```
````

## Import & reference content

### Markdown partials

If a certain piece of content must be re-used across multiple documents in the
exact form, it's a good idea to turn it into a partial. Thanks to that, you
maintain content in a single file, instead of multiple instances of the same
content in many docs.

Add partials to the `_common` directory.

To import a partial, use this `mdx-code-block`:

````md
```mdx-code-block
import ExamplePartial from './_common/example.md'

<ExamplePartial />
```
````

> **TIP:** Headings contained in partials aren't added to the Docusaurus table
> of contents (ToC). To make sure users can access all headings through the ToC,
> don't add headings to partials. Instead, add appropriate headings to the
> document manually and introduce partials after them. To see an implementation
> of this approach, look at
> [this file](https://github.com/ory/docs/blob/0137302d511b2a6b0e17a570e917d92fcdff1d1f/docs/kratos/social-signin/10_google.mdx?plain=1#L237).

### Code snippets

#### From GitHub

Use
[CodeFromRemote](https://github.com/ory/docusaurus-template/blob/master/src/theme/CodeFromRemote.js)
to import code directly from GitHub.

Use this `mdx-code-block`:

````md
```mdx-code-block
import CodeFromRemote from '@theme/CodeFromRemote'

<CodeFromRemote
  lang="js"
  link="https://github.com/ory/kratos-selfservice-ui-node/blob/master/src/middleware/simple.ts"
  src="https://raw.githubusercontent.com/ory/kratos-selfservice-ui-node/master/src/middleware/simple.ts"
  startAt="{CONTENT_FROM_CODE}"
  endAt="{CONTENT_FROM_CODE}"
/>
```
````

- `lang` specifies the programming language the code is in
- `link` is the file location displayed in the top part of the code block window
- `src` is the direct link used to import the code (optional)
- `startAt` , `endAt` are used to define where the imported snippet starts and
  ends (optional)

#### From this repository

````md
```mdx-code-block
import CodeBlock from '@theme/CodeBlock'
import exampleJs from '!!raw-loader!./code-example.jsx'
import exampleGo from '!!raw-loader!./code-example.go'

<CodeBlock className="language-jsx">{exampleJs}</CodeBlock>
<CodeBlock className="language-go">{exampleGo}</CodeBlock>
```
````

## Screenshots and videos

- Use screenshots and videos sparingly. These resources tend to get out-of-date
  quickly and are cumbersome to maintain.
- Screenshots and videos must capture only the relevant parts of the screen.
- Screenshots and videos must capture UI elements in English. If you’re
  capturing parts of the browser UI in your work, make sure the UI is in
  English.
- Make an effort to get the screenshots and videos looking as clean as possible.
  Avoid situations where text fields suggest irrelevant inputs, avoid erratic
  mouse cursor movements and general chaos.
- You must add media to `_static` folders.
  - In the `_static` directory, each document that uses media has its own
    directory.
  - In the directory of the document, the files have numbers for names, for
    example, `1.png`, `2.png`, `3.png`. The filenames should reflect the stage
    at which the media is used in the document. This means that the screenshot
    named `1.png` will be used in line 70, while the diagram `2.svg` will be
    used in line 100.

### Compressing images

Compress images you add to the documentation to keep the repository lean. You
can use [`pngquant`](https://pngquant.org/).
[Read this article to learn a trick to make your screenshots 80% smaller](https://about.gitlab.com/blog/2020/01/30/simple-trick-for-smaller-screenshots/).

### Recording and compressing videos

We recommend using
[Quicktime to record videos](https://support.apple.com/en-gb/guide/quicktime-player/qtp97b08e666/mac).
Follow these rules:

- Use 16:9 format with at least 1024 pixels of width. `ffmpeg` will scale it to
  the right size.
- Make sure that no history or auto-suggestions are visible.

After recording the video, convert the `.mov` file to `mp4` and `webm`:

```shellsession
file="screencast.mov"

ffmpeg -i $file -an -c:v libvpx-vp9 -vf scale=1024:-1 -crf 30 -b:v 0 "${file%.*}".webm
ffmpeg -i $file -vcodec h264 -vf scale=1024:-1 -an "${file%.*}".mp4
```

Use this `mdx-code-block` to add the video to your document:

````
```mdx-code-block
import mp4 from './_static/screencast.mp4'
import webm from './_static/screencast.webm'
import VideoEmbed from '@site/src/components/VideoEmbed'

<VideoEmbed mp4={mp4} webm={webm} />
```
````

## Ory Console

### Navigate to Ory Console Pages

You can use the `/current/` route to navigate users to their active Ory Network
project. For example, to access the Custom UI settings for the active Ory
Network project in the Console, you can link to:
https://console.ory.com/projects/current/ui

When referencing a page of the Ory Console, use the
`<ConsoleLink route="project..." />` component in MDX files.

The component resolves the navigation section and page title for the given
route, and renders a standard markup for both, as well as the link with the
`/current/` shortcut mentioned above:

```tsx
<ConsoleLink route="project.activity.events" />

// becomes:
// Activity → Logs & Events in the [Ory Console](https://console.ory.com/current/projects/activity/events)
```

A list of all supported routes can be found here:
[src/components/ConsoleLink/console-routes.ts](src/components/ConsoleLink/console-routes.ts).

Please note that the syntax is like accessing a path in a JS object, but as a
string. If the route you want to reference is found in the `console-routes.ts`
file in the following way:

```ts
{
  project: {
    activity: {
      events: {
        route: "/projects/[project]/activity/events",
      }
    }
  }
}
```

Use `<ConsoleLink route="project.activity.events" />` to reference it.

To add a new route, you need to add an entry in
[`console-routes.ts`](https://github.com/ory/docs/blob/master/src/components/ConsoleLink/console-routes.ts)
as well as
[`console-nav-data.ts`](https://github.com/ory/docs/blob/master/src/components/ConsoleLink/console-nav-data.ts).

## Testing

To test the documentation locally:

1. Clone this repository.
2. Navigate to the cloned repository and run `npm install` to install all
   dependencies.
3. Run the development server and test the changes you made using a fully
   operational version of the documentation portal that runs on your machine.
   Run `npm run start`.
4. Create a production build to check for any technical issues, such as invalid
   internal links. Run `npm run build`.

### Redirects

When the URL of a document changes, you must set up a redirect to preserve SEO
and prevent broken links. Without redirects, the original URL returns a 404
error, breaking existing links from external sites and causing search engines to
lose page authority.

The rule is: if the URL in the browser changes, add a redirect. If it doesn't,
no redirect is required.

Filenames don't always determine URLs. Ory documentation uses numbered prefixes
in filenames and sets URLs explicitly in the front matter. Renaming with no
other changes doesn't require a redirect because the final URL stays the same.

You must add a redirect when you

- change the `slug` or `id` property in the document front matter
- delete a document
- move a document to a different directory (if it changes the URL path)

#### How to add a redirect

Add redirects to the vercel.json file in the repository root. Use this format:

```json
{
  "redirects": [
    {
      "source": "/docs/old-path",
      "destination": "/docs/new-path",
      "permanent": false
    }
  ]
}
```

- Start with permanent: false (302 redirect) until you confirm the redirect
  works in the preview or production environment.
- Change to permanent: true (301 redirect) after you verify the redirect
  functions correctly.
- Test the redirect in the Vercel preview deployment before merging.

## Formatting documentation

All documents and other files in this repository must be formatted with Prettier
using the [Ory Prettier styles](https://github.com/ory/prettier-styles).

To format all relevant files, run these commands from the main directory of the
```sh
make format
git commit -a -m "chore: format"
git push
```

For a better workflow, install the Prettier plugin for your editor:

- [VSCode Prettier plugin](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
- [IntelliJ Prettier plugin](https://www.jetbrains.com/help/idea/prettier.html)

## Adding content to "Examples" page

[The Quickstart overview](https://www.ory.sh/docs/getting-started/overview)
provides an overview of Ory quickstarts. To add a new example or modify existing
entries:

1.  Open `examples-content.tsx` in `src/pages/_assets/`.
2.  Copy the following snippet and append it to the correct array (either
    official, community, or self-hosting examples):

    ```tsx
    {
          title: "Protect a Page with Login: NextJs/React", //Your example title goes here
          language: "typescript",                           //The main programming language of your example
          author: "ory",                                    //The author's GitHub handle
          tested: true,                                     //Is the example in ory/examples or ory/docs and has automated tests?
          repo: "https://github.com/ory/docs/tree/master/code-examples/protect-page-login/nextjs", //The repo containing the example code
          docs: "https://www.ory.sh/docs/guides/protect-page-login/next.js",                       //Documentation for the example, can be README, blog article or similar
        },
    ```

    - `language` can be one of: dart, django, docker, erlang, flutter, go, java,
      javascript, kotlin, kubernetes, nextjs, nodejs, ory, php, python, react,
      rescript, svelte, typescript, vue

3.  Open a pull request with your changes.

## CLI and API reference - auto-generated content

Ory documentation contains auto-generated content such as CLI and API
references. Documents of this type are generated from source code and are pushed
to this repository by an automated job.

As such, editing any of these documents in the Ory documentation repository
isn't the way to change or fix this content. Any changes you make will be
overwritten by the next push that follows the generation process.

Instead, find the lines in question in the source code of the Ory projects and
edit them there. For example, if you want to edit the documentation of the Ory
Kratos CLI, you must edit this file:

https://github.com/ory/kratos/blob/master/cmd/clidoc/main.go

The `cmd/clidoc/main.go` is the general path for all Ory projects.

The command to generate the CLI docs can be found here:
https://github.com/ory/x/blob/master/clidoc/generate.go#L96