bland-finland-95044
05/09/2025, 4:11 PMbrief-egg-61061
05/09/2025, 4:11 PMbrief-egg-61061
05/09/2025, 4:11 PMtoSession()
method to verify if the user has an active session. If the session is invalid or expired, redirect the user to the login page. 2. Provide a logout mechanism that uses the Ory logout flow. Use the createBrowserLogoutFlow()
method to generate a logout URL, and direct the user to this URL to terminate their session. Here’s a practical example from the Ory documentation: jsx import React, { useEffect, useState } from "react" import { FrontendApi, Configuration, Session, Identity } from "@ory/client" const basePath = process.env.REACT_APP_ORY_URL || "<http://localhost:4000>" const ory = new FrontendApi( new Configuration({ basePath, baseOptions: { withCredentials: true, }, }), ) function App() { const [session, setSession] = useState<Session | undefined>() const [logoutUrl, setLogoutUrl] = useState<string | undefined>() useEffect(() => { ory .toSession() .then(({ data }) => { setSession(data) ory.createBrowserLogoutFlow().then(({ data }) => { setLogoutUrl(data.logout_url) }) }) .catch(() => { // Redirect to login if session is invalid/expired window.location.replace(`${basePath}/ui/login`) }) }, []) if (!session) { return <h1>Loading...</h1> } return ( <div> <p>Welcome, {session.identity.traits.email}</p> <a href={logoutUrl}>Logout</a> </div> ) } export default App
Key points: - The session is checked on load; if invalid, the user is redirected to login. - The logout link uses the Ory-generated logout URL, ensuring the session is properly terminated. This approach ensures that users are logged out both when they explicitly click "Logout" and when their session is no longer valid, providing a secure and seamless experience in your React application [Integrate authentication into React](https://www.ory.sh/docs/getting-started/integrate-auth/react#require-login-to-access-the-app-page).bland-finland-95044
06/16/2025, 11:38 PMbrief-egg-61061
06/16/2025, 11:38 PMbrief-egg-61061
06/16/2025, 11:38 PMbland-finland-95044
06/17/2025, 12:00 AMbrief-egg-61061
06/17/2025, 12:00 AMbrief-egg-61061
06/17/2025, 12:00 AMbland-finland-95044
06/21/2025, 1:58 AMbrief-egg-61061
06/21/2025, 1:58 AMbrief-egg-61061
06/21/2025, 1:58 AMtypescript class Document implements Namespace { related: { parents: Folder[] } permits = { view: (ctx: Context): boolean => this.related.parents.traverse((parent) => parent.permits.view(ctx)), } }
In this example, the Document's view permission checks the view permission on its related Folder(s), which is a different namespace. This pattern is supported and is a core part of how OPL enables hierarchical and cross-namespace permission checks [Define permissions in the OPL](https://www.ory.sh/docs/keto/modeling/create-permission-model#define-permissions-in-the-opl) [Ory Permission Language specification](https://www.ory.sh/docs/keto/reference/ory-permission-language#statements). Summary: Yes, OPL allows you to make permission decisions based on permits in a different namespace by traversing relationships and invoking permissions on related objects in those namespaces.bland-finland-95044
06/21/2025, 2:06 AMbrief-egg-61061
06/21/2025, 2:06 AMbrief-egg-61061
06/21/2025, 2:06 AMtraverse
function in Ory Permission Language (OPL) is used to evaluate permissions or relations across related objects, typically in hierarchical or graph-like structures. It allows you to delegate a permission check from one object to its related objects, often in a different namespace. For example, if a Document
has one or more parent `Folder`s, and you want to allow a user to view the Document
if they can view any of its parent `Folder`s, you would use traverse
like this: typescript class Document implements Namespace { related: { parents: Folder[] } permits = { view: (ctx: Context): boolean => this.related.parents.traverse((parent) => parent.permits.view(ctx)), } }
In this example, this.related.parents.traverse((parent) => parent.permits.view(ctx))
checks the view
permission on each parent Folder
. If any parent grants the permission, the check returns true
for the Document
as well [Define permissions in the OPL](https://www.ory.sh/docs/keto/modeling/create-permission-model#define-permissions-in-the-opl) [OPL Examples](https://www.ory.sh/docs/keto/reference/ory-permission-language#examples). This is especially useful for implementing permission inheritance in hierarchies, such as folders and files, or organizational structures. Summary: The traverse
function lets you propagate permission checks through related objects, enabling flexible and hierarchical access control models in OPL.bland-finland-95044
06/21/2025, 2:10 AMbrief-egg-61061
06/21/2025, 2:10 AMbrief-egg-61061
06/21/2025, 2:10 AMUser
, Document
, Folder
), and each namespace contains the relationships and permissions relevant to that resource type. This approach is shown in multiple examples, such as document stores and RBAC models, where each resource type (like Document
, Folder
, Group
, etc.) has its own namespace [Namespaces](https://www.ory.sh/docs/keto/concepts/namespaces) [Create a permission model](https://www.ory.sh/docs/keto/modeling/create-permission-model). Regarding inheritance: The Ory Permission Language (OPL) does not currently support class inheritance or interface extension in the way that TypeScript or object-oriented languages do. Each namespace (class) is defined independently, and there is no mechanism in OPL to inherit relations or permissions from another namespace to "make it cleaner." All relationships and permissions must be explicitly declared in each namespace [Ory Permission Language specification](https://www.ory.sh/docs/keto/reference/ory-permission-language#statements). Summary: - Yes, applications usually have a namespace for every type of permission-protected resource. - There is no built-in inheritance mechanism in OPL; each namespace must explicitly declare its own relationships and permissions. - You can, however, use patterns like permission delegation (e.g., using traverse
) to reduce duplication in permission logic, but not in the structure of the namespace definitions themselves.bland-finland-95044
06/21/2025, 2:17 AMbrief-egg-61061
06/21/2025, 2:17 AMbrief-egg-61061
06/21/2025, 2:17 AMclass ConditionTemplate extends FeatureResource
). Each namespace must be defined independently, and there is no mechanism to inherit relations or permissions from another namespace [Ory Permission Language specification](https://www.ory.sh/docs/keto/reference/ory-permission-language#statements). 2. Accessing relations and permissions: In OPL, you must access relations and permissions through the this.related
and this.permits
properties. For example, to check a permission on related features, you would use something like: typescript this.related.features.traverse((feature) => feature.permits.active(ctx))
Directly calling this.features.active(ctx.subject)
is not valid OPL syntax. 3. Relation declaration syntax: Relations must be declared inside the related
property, and permissions inside the permits
property, both within the class definition. The syntax must follow the OPL rules [OPL Statements](https://www.ory.sh/docs/keto/reference/ory-permission-language#statements). A corrected OPL example (without inheritance) might look like: typescript class Feature implements Namespace { permits = { active: (ctx: Context): boolean => { // logic for active permission } } } class ConditionTemplate implements Namespace { related: { features: Feature[] } permits = { active: (ctx: Context): boolean => this.related.features.traverse((feature) => feature.permits.active(ctx)) } }
Summary: - OPL does not support class inheritance (extends
). - You must use this.related
and traverse
to check permissions on related objects. - Each namespace must be defined independently. If you need to share permission logic, you must duplicate it in each namespace or use permission delegation patterns, but not inheritance [Namespaces](https://www.ory.sh/docs/keto/concepts/namespaces) [OPL Examples](https://www.ory.sh/docs/keto/reference/ory-permission-language#examples).bland-finland-95044
06/23/2025, 8:43 PMimport { Namespace, SubjectSet, Context } from "@ory/keto-namespace-types";
class User implements Namespace { }
class Customer implements Namespace {
related: {
members: (User | Customer)[];
};
}
// An Application to grant permissions to
class Application implements Namespace {
related: {
// Users or Customers that can use this Application
users: (User | SubjectSet<Customer, "members">)[];
// Application-level admins
superadmins: User[];
};
permits = {
use: (ctx: Context): boolean => this.related.users.includes(ctx.subject),
superadmin: (ctx: Context): boolean => this.related.superadmins.includes(ctx.subject),
};
}
class Package implements Namespace {
related: {
// Users or customers entitled for this package (and all the features it contains)
// We can also add a package to another package to enable package "inheritance"
entitled: (User | SubjectSet<Customer, "members"> | SubjectSet<Package, "entitled">)[];
};
permits = {
entitled: (ctx: Context): boolean => this.related.entitled.includes(ctx.subject),
};
}
class Feature implements Namespace {
related: {
// Users, customers, or package subscribers entitled for this Feature
entitled: (User | SubjectSet<Customer, "members"> | SubjectSet<Package, "entitled"> | SubjectSet<Application, "users">)[];
// Feature flag is enabled for these users - could be by role in the future
enabled: (User | SubjectSet<Customer, "members"> | SubjectSet<Application, "users">)[];
// For now only superadmins can edit features. This will probably change once roles are implemented
editors: (SubjectSet<Application, "superadmins">)[];
};
permits = {
entitled: (ctx: Context): boolean => this.related.entitled.includes(ctx.subject),
enabled: (ctx: Context): boolean => this.related.enabled.includes(ctx.subject),
// Feature flag is enabled AND feature is entitled
active: (ctx: Context): boolean => this.permits.enabled(ctx) && this.permits.entitled(ctx),
edit: (ctx: Context): boolean => this.related.editors.includes(ctx.subject),
};
}
// A resource that belongs to a specific feature
// could potentially be more specific in the future
class FeatureResource implements Namespace {
related: {
features: Feature[]
}
permits = {
read: (ctx: Context): boolean => this.related.features.traverse((parent) => parent.permits.active(ctx)),
}
}
brief-egg-61061
06/23/2025, 8:43 PMbrief-egg-61061
06/23/2025, 8:43 PMFeatureResource
objects a given customer has read
access to, you need to use Ory Keto's List API to find all FeatureResource
objects where the customer is entitled to the underlying Feature
(i.e., where the read
permission is granted). ### Using the Keto CLI You can use the CLI to list all FeatureResource
objects a customer has read
access to by querying for relation tuples where: - namespace
is FeatureResource
- relation
is read
- subject
is your customer (e.g., customers:customer-id
) The CLI command would look like: sh keto relation-tuple get --namespace FeatureResource --relation read --subject-id customers:customer-id --format json --read-remote <keto-read-api-url>
This will return all FeatureResource
objects for which the given customer has the read
permission, resolving all the permission logic (including traversing to the Feature
and checking active
) as defined in your OPL model [Display all objects a user has access to](https://www.ory.sh/docs/keto/guides/list-api-display-objects) [RBAC: Display all objects a user has access to](https://www.ory.sh/docs/keto/guides/rbac#display-all-objects-a-user-has-access-to). ### Using the Go SDK With the Go SDK, you would use the ListRelationTuples
API to perform the same query. Here’s a simplified example: go import ( "context" "fmt" keto "<http://github.com/ory/keto-client-go|github.com/ory/keto-client-go>" ) func main() { configuration := keto.NewConfiguration() configuration.Servers = []keto.ServerConfiguration{ {URL: "<http://127.0.0.1:4466>"}, // Replace with your Keto read API URL } client := keto.NewAPIClient(configuration) namespace := "FeatureResource" relation := "read" subjectId := "customers:customer-id" // Replace with your customer ID resp, _, err := client.RelationTupleApi.GetRelationTuples(context.Background()). Namespace(namespace). Relation(relation). SubjectId(subjectId). Execute() if err != nil { panic(err) } for _, tuple := range resp.RelationTuples { fmt.Printf("Customer has read access to FeatureResource: %s\n", tuple.Object) } }
This will list all FeatureResource
objects the customer can read, according to your permission model [Go SDK example](https://www.ory.sh/docs/keto/self-hosted/go). --- Note: - The permission logic (including traversing from FeatureResource
to Feature
and checking active
) is handled by Keto according to your OPL model. You do not need to manually resolve the permission tree; just query for the read
relation as shown above. - If you use subject sets (e.g., SubjectSet<Customer, "members">
), Keto will resolve those as part of the permission check. If you need to list all objects a user (or customer) has access to, this is the recommended approach in Ory Keto [List API: display all objects a user has access to](https://www.ory.sh/docs/keto/guides/list-api-display-objects).bland-finland-95044
06/23/2025, 8:50 PMketo expand access files /photos/beach.jpg --format json-pretty --max-depth 3 --insecure-disable-transport-security
brief-egg-61061
06/23/2025, 8:50 PMbrief-egg-61061
06/23/2025, 8:50 PMsh keto expand access files /photos/beach.jpg --format json-pretty --max-depth 3 --insecure-disable-transport-security
This command is valid and will output the expansion tree for the access
relation on the object /photos/beach.jpg
in the files
namespace, showing all subjects who have access, up to a depth of 3. The --insecure-disable-transport-security
flag is required if you are running Keto without TLS, as noted in the documentation [Expand API: display who has access to an object](https://www.ory.sh/docs/keto/guides/expand-api-display-who-has-access#example) [keto expand](https://www.ory.sh/docs/keto/cli/keto-expand#keto-expand). You can also specify the output format (e.g., json-pretty
) and the maximum depth of the expansion tree with --max-depth
. Summary: The command you provided is correct for expanding and visualizing access permissions using the Ory Keto CLI.bland-finland-95044
06/23/2025, 8:50 PMketo expand access files /photos/beach.jpg --format json-pretty --max-depth 3 --insecure-disable-transport-security
brief-egg-61061
06/23/2025, 8:50 PMbrief-egg-61061
06/23/2025, 8:50 PMketo expand
command is specific to self-hosted Ory Keto and is not available in the Ory CLI for Ory Network. The Ory CLI provides its own set of commands for interacting with Ory Network resources, and there is no documentation indicating that you can use keto expand
or an equivalent expand command directly with Ory Network via the Ory CLI. The knowledge sources do not mention support for the keto expand
command or an equivalent in the Ory CLI when connected to Ory Network. Therefore, you cannot use the keto expand
command with Ory Network using the Ory CLI [ory CLI reference](https://www.ory.sh/docs/cli/ory) [keto expand reference](https://www.ory.sh/docs/keto/cli/keto-expand#keto-expand). If you need to perform similar operations in Ory Network, you would need to use the available Ory CLI commands or APIs specific to Ory Network, but the expand functionality as described for self-hosted Keto is not documented for Ory Network.