bumpy-controller-43157
05/07/2025, 6:41 AMbrief-egg-61061
05/07/2025, 6:41 AMbrief-egg-61061
05/07/2025, 6:41 AMGroup
namespace and relate users to groups as members, and then use these relationships to drive access control decisions in your application. This approach is scalable and supports complex scenarios, including RBAC and group hierarchies [Get started with Ory Permissions](https://www.ory.sh/docs/guides/permissions/overview), [Role Based Access Control (RBAC)](https://www.ory.sh/docs/keto/guides/rbac). However, by default, Ory Network does not automatically include group or role information from Ory Keto (Permissions) in the ID or access tokens (JWTs) issued via OIDC. The standard OIDC token only includes basic claims (like email) and not custom relationships such as group memberships, even if you request scopes like groups
[Getting Groups claims via OIDC](https://github.com/ory/network/issues/267). Scalable solution: - Model groups/roles in Ory Permissions: Use OPL to define group/role relationships. - Populate tokens with group/role claims: To include group/role information in the ID/access token, you need to implement a custom consent endpoint. This endpoint can fetch the user's group memberships from Ory Keto and add them as claims to the token. Ory provides a guide for creating a custom consent UI/endpoint, which gives you full control over what data is included in the tokens [Getting Groups claims via OIDC](https://github.com/ory/network/issues/267), [Default Consent UI should be able to populate ID token from traits](https://github.com/ory/network/issues/261). > “To populate the ID token with any data you want, you can write a custom consent endpoint. ... Using a custom consent endpoint, you can basically say what data goes into your tokens.” > — [Getting Groups claims via OIDC](https://github.com/ory/network/issues/267) Summary: - Assign groups/roles using Ory Permissions and OPL. - Implement a custom consent endpoint to inject group/role claims into the JWTs. - This approach is scalable and flexible, but requires some custom development for the consent flow. If you need more details on how to implement the custom consent endpoint, refer to the [Ory Hydra custom consent UI guide](https://www.ory.sh/docs/hydra/guides/custom-ui-oauth2) as referenced in the GitHub issue.bumpy-controller-43157
05/07/2025, 7:26 AMbrief-egg-61061
05/07/2025, 7:26 AMbrief-egg-61061
05/07/2025, 7:27 AMory update opl
or ory patch opl
command. These commands allow you to upload your OPL (TypeScript) file to your Ory Network project, updating the permission rules. Example using the Ory CLI: sh ory update opl --file /path/to/namespace_config.ts --project <project-id>
Or, using the patch command: sh ory patch opl --file /path/to/namespace_config.ts --project <project-id>
You can also specify the workspace if needed: sh ory update opl --file /path/to/namespace_config.ts --project <project-id> --workspace <workspace-id>
- The --file
flag points to your OPL TypeScript file. - The --project
flag specifies your Ory Network project. - The --workspace
flag is optional if you have multiple workspaces. What happens: This command uploads your OPL file, and the permission rules defined in it will be applied to your project. Legacy namespace definitions will be overwritten by this operation [ory update opl](https://www.ory.sh/docs/cli/ory-update-opl#ory-update-opl), [ory patch opl](https://www.ory.sh/docs/cli/ory-patch-opl#ory-patch-opl). Note: Make sure your OPL file is valid and follows the Ory Permission Language specification. For more details, see the official documentation for [ory update opl](https://www.ory.sh/docs/cli/ory-update-opl#ory-update-opl) and [ory patch opl](https://www.ory.sh/docs/cli/ory-patch-opl#ory-patch-opl).bumpy-controller-43157
05/07/2025, 7:44 AMbrief-egg-61061
05/07/2025, 7:44 AMbrief-egg-61061
05/07/2025, 7:44 AMUser
, Role
, and Resource
namespaces. Users are assigned to roles, and roles are granted permissions on resources. The permissions are checked by traversing the relationships. typescript import { Namespace, Context, SubjectSet } from "@ory/keto-namespace-types" class User implements Namespace { related: { roles: SubjectSet<Role, "members">[] } } class Role implements Namespace { related: { members: User[] } } class Resource implements Namespace { related: { roles: SubjectSet<Role, "members">[] } permits = { view: (ctx: Context): boolean => this.related.roles.includes(ctx.subject), edit: (ctx: Context): boolean => this.related.roles.includes(ctx.subject), } }
How it works: - Users are related to roles via the roles
relation. - Roles have members (users). - Resources grant permissions (view
, edit
) to roles. - Permission checks (e.g., view
) verify if the subject (user) is included in the resource's roles. This model can be extended for more granular permissions or hierarchical roles as needed. For more details and examples, see the [Ory Permission Language specification](https://www.ory.sh/docs/keto/reference/ory-permission-language#examples) and the [RBAC guide](https://www.ory.sh/docs/keto/guides/rbac).bumpy-controller-43157
05/07/2025, 7:53 AMbrief-egg-61061
05/07/2025, 7:53 AMbrief-egg-61061
05/07/2025, 7:54 AMTS2502: 'roles' is referenced directly or indirectly in its own type annotation.
typically occurs in TypeScript when a type is recursively referencing itself in a way that TypeScript cannot resolve. In the Ory Permission Language (OPL), when you want to relate a User
to a Role
via a relation, you should use the SubjectSet
type to avoid direct recursive references. The correct way to express that a user is a member of a role is to have the User
reference a SubjectSet<Role, "members">[]
, and the Role
have a members: User[]
relation. This pattern is shown in the official OPL examples and avoids the TypeScript recursion issue. Here is a corrected OPL snippet for simple RBAC, following the official documentation: typescript import { Namespace, Context, SubjectSet } from "@ory/keto-namespace-types" class User implements Namespace {} class Role implements Namespace { related: { members: User[] } } class Resource implements Namespace { related: { roles: SubjectSet<Role, "members">[] } permits = { view: (ctx: Context): boolean => this.related.roles.includes(ctx.subject), edit: (ctx: Context): boolean => this.related.roles.includes(ctx.subject), } }
- The User
class does not have a roles
relation; instead, the Role
class has a members
relation to User[]
. - The Resource
class relates to roles using SubjectSet<Role, "members">[]
, which is the recommended way to express this in OPL and avoids the TypeScript error. This approach is consistent with the OPL examples provided in the [Ory Permission Language specification](https://www.ory.sh/docs/keto/reference/ory-permission-language#examples). If you need to check if a user has a permission on a resource, you would check if the user is a member of a role that is related to the resource, as shown above. This avoids the recursive type issue and is the recommended modeling pattern in Ory Permissions.bumpy-controller-43157
05/07/2025, 7:57 AMbrief-egg-61061
05/07/2025, 7:57 AMbrief-egg-61061
05/07/2025, 7:57 AMResource
and using Role
namespaces for user
and admin
roles is a recommended and scalable approach with Ory Permissions. This allows you to define fine-grained access control and easily manage which users have which roles for your API [Role Based Access Control (RBAC)](https://www.ory.sh/docs/keto/guides/rbac). Assigning roles to users (e.g., restapi:user
): 1. Model roles and relationships: - Define a Role
namespace for your API (e.g., restapi:user
, restapi:admin
). - Assign users to these roles by creating relationships (tuples) such as Role:restapi:user#members@User:alice
. 2. Example relationship tuple (using Ory CLI): json { "namespace": "Role", "object": "restapi:user", "relation": "members", "subject_id": "User:alice" }
This means Alice is a member of the restapi:user
role. 3. Apply permission rules: - In your OPL file, define which roles have which permissions on the API resources. Including roles in the access/ID token: By default, Ory Network does not automatically include group or role information from Ory Permissions in the access or ID tokens. To include this information, you need to implement a custom consent endpoint. This endpoint can fetch the user's roles from Ory Keto (Permissions) and add them as claims to the token. This is the officially recommended approach for custom claims in tokens [Getting Groups claims via OIDC](https://github.com/ory/network/issues/267). > “To populate the ID token with any data you want, you can write a custom consent endpoint. ... Using a custom consent endpoint, you can basically say what data goes into your tokens.” > — [Getting Groups claims via OIDC](https://github.com/ory/network/issues/267) Summary: - Use Ory Permissions to model roles and assign users to them. - Use the Ory CLI or API to create the necessary relationship tuples. - Implement a custom consent endpoint to include the user's roles in the access/ID token. If you need a step-by-step guide for the custom consent endpoint, refer to the [Ory Hydra custom consent UI guide](https://www.ory.sh/docs/hydra/guides/custom-ui-oauth2) as referenced in the GitHub issue. The knowledge sources do not provide a ready-made example for this, but this is the documented and supported approach.bumpy-controller-43157
05/07/2025, 8:14 AMbrief-egg-61061
05/07/2025, 8:14 AMbrief-egg-61061
05/07/2025, 8:14 AMory update opl
command using environment variables. According to the migration guide for Ory CLI v1, you can set the ORY_PROJECT
and ORY_WORKSPACE
environment variables, and the CLI will use these as the context for your commands. For example: sh export ORY_PROJECT=<project-id> export ORY_WORKSPACE=<workspace-id> ory update opl --file /path/to/namespace_config.ts
This approach is supported for all relevant Ory CLI commands, including ory update opl
[Migrate existing scripts and automation](https://www.ory.sh/docs/guides/cli/cli-migration-v1#migrate-existing-scripts-and-automation).bumpy-controller-43157
05/07/2025, 8:23 AMbrief-egg-61061
05/07/2025, 8:23 AMbrief-egg-61061
05/07/2025, 8:23 AMory update opl
command indicates that your credentials do not have the necessary permissions to perform this action. This typically happens if your API key or authentication context does not have sufficient rights to update the OPL configuration in the specified project or workspace. Troubleshooting steps: 1. Check your API key: Ensure you are using a valid workspace or project API key with the correct permissions. Workspace API keys are required for managing project configurations, including OPL updates. Set the key using the ORY_WORKSPACE_API_KEY
environment variable as described in the documentation. 2. Verify context: Make sure you are targeting the correct project and workspace by setting the ORY_PROJECT
and ORY_WORKSPACE
environment variables, or by using the --project
and --workspace
flags. 3. Authentication: If you are running the command in a CI/CD environment, double-check that the secrets are correctly configured and available to the process. 4. Permissions: Only users or API keys with sufficient permissions can update OPL. If you are unsure about your permissions, try authenticating with a different account or key that has admin rights on the workspace or project. The knowledge sources confirm that insufficient permissions will result in a "forbidden" error for update actions, and that correct API key usage is required for configuration management tasks [Basic functionality](https://www.ory.sh/docs/guides/cli/cli-basics), [Manage Ory Network configuration in git](https://www.ory.sh/docs/guides/gitops). If you have verified all of the above and still encounter the issue, you may need to review your workspace/project access rights in the Ory Console or contact your Ory administrator.bumpy-controller-43157
05/07/2025, 11:33 AMbrief-egg-61061
05/07/2025, 11:33 AMbrief-egg-61061
05/07/2025, 11:33 AMfoo@bar.baz
the role demo:admin
for the resource demo-api
, you would create a relationship (relation tuple) that expresses: - The user is a member of the demo:admin
role. - The demo-api
resource grants permissions to the demo:admin
role. Here’s how you can represent this in Ory’s relation tuple notation: Role:demo:admin#members@User:foo@bar.baz Resource:demo-api#roles@Role:demo:admin
- The first line means: user foo@bar.baz
is a member of the demo:admin
role. - The second line means: the demo-api
resource is related to the demo:admin
role (for example, for permission checks). This pattern follows the RBAC modeling described in the Ory documentation, where users are assigned to roles, and roles are related to resources for permission checks [Role Based Access Control (RBAC)](https://www.ory.sh/docs/keto/guides/rbac), [Relationships](https://www.ory.sh/docs/keto/concepts/relation-tuples). If you want to create this relationship using the Ory CLI, you would use a command similar to: sh echo "Role:demo:admin#members@User:foo@bar.baz" | ory parse relation-tuples --project <project-id> --workspace <workspace-id> --format=json | ory create relation-tuples --project <project-id> --workspace <workspace-id>
This approach is directly supported by the Ory Permissions model and CLI [Manage relation tuples](https://www.ory.sh/docs/guides/cli/configure-permission-service#manage-relation-tuples).bumpy-controller-43157
05/07/2025, 11:34 AMbrief-egg-61061
05/07/2025, 11:34 AMbrief-egg-61061
05/07/2025, 11:34 AMfoo@bar.baz
is a member of the demo:admin
role, and demo:admin
is a role for the resource demo-api
, in JSON format suitable for Ory Keto: json [ { "namespace": "Role", "object": "demo:admin", "relation": "members", "subject_id": "User:foo@bar.baz" }, { "namespace": "Resource", "object": "demo-api", "relation": "roles", "subject_set": { "namespace": "Role", "object": "demo:admin", "relation": "members" } } ]
- The first object assigns the user to the demo:admin
role. - The second object relates the demo-api
resource to the demo:admin
role using a subject set, which is the recommended way to model RBAC in Ory Keto [Role Based Access Control (RBAC)](https://www.ory.sh/docs/keto/guides/rbac), [Relationships](https://www.ory.sh/docs/keto/concepts/relation-tuples). If you need to import these relationships, you can use the Ory CLI as described in the documentation.bumpy-controller-43157
05/07/2025, 11:40 AMbrief-egg-61061
05/07/2025, 11:40 AMbrief-egg-61061
05/07/2025, 11:41 AMmember
(or your equivalent role membership relation). This will return all roles (or groups) the user belongs to. How to do this: - REST API: You can make a request to the Keto List API endpoint, filtering by the user's subject ID and the member
relation. - Java/Spring: Use a standard HTTP client (like RestTemplate
or WebClient
) to call the Keto REST API from your Java/Spring application. Example (conceptual): http GET /relation-tuples?subject=User:foo@bar.baz&relation=member
This will return all tuples where foo@bar.baz
is a member, i.e., all roles/groups the user is assigned to. Relevant documentation: - The Keto List API allows you to "list objects a user has access to" or "list users who have a specific role" by querying relationships with partial information, such as the subject and relation. This is the recommended approach for your use case [API overview](https://www.ory.sh/docs/keto/concepts/api-overview), [List API: display all objects a user has access to](https://www.ory.sh/docs/keto/guides/list-api-display-objects). For use in an OAuth2 webhook: You can call this API from your webhook handler, extract the roles from the response, and use them as needed in your OAuth2 flow. > The knowledge sources do not provide a direct Java code example, but the REST API approach is fully supported and can be easily integrated with Java/Spring using standard HTTP clients.bumpy-controller-43157
05/07/2025, 11:45 AMbrief-egg-61061
05/07/2025, 11:45 AMbrief-egg-61061
05/07/2025, 11:45 AMUser
and Role
as referencing each other directly. Instead, model the relationship so that only the User
has a roles
relation, and the Role
does not have a members
relation. This approach is valid and avoids the TypeScript cyclic type error. Here’s how you can define it: typescript import { Namespace, Context, SubjectSet } from "@ory/keto-namespace-types" class User implements Namespace { related: { roles: Role[] } } class Role implements Namespace {} class Resource implements Namespace { related: { roles: Role[] } permits = { view: (ctx: Context): boolean => this.related.roles.includes(ctx.subject), edit: (ctx: Context): boolean => this.related.roles.includes(ctx.subject), } }
- The User
class has a roles
relation to Role[]
. - The Role
class does not have a members
relation, breaking the cycle. - The Resource
class can relate to roles for permission checks. This structure is consistent with the OPL specification, which allows you to define many-to-many relationships in one direction to avoid cyclic references and TypeScript errors [Ory Permission Language specification](https://www.ory.sh/docs/keto/reference/ory-permission-language#statements). If you need to check which roles a user has, you can query the roles
relation from the User
namespace. This approach is scalable and avoids the cyclic type error.bumpy-controller-43157
05/07/2025, 11:49 AMbrief-egg-61061
05/07/2025, 11:49 AMbrief-egg-61061
05/07/2025, 11:49 AMdemo:admin
role to the user foo@bar.baz
in Ory Permissions (Keto), you create a relationship (relation tuple) where the user is a member of the role. In JSON format, this relationship looks like: json { "namespace": "roles", "object": "demo:admin", "relation": "member", "subject_id": "foo@bar.baz" }
- `namespace`: The namespace for roles (commonly named roles
). - `object`: The specific role, here demo:admin
. - `relation`: The relation type, typically member
for role assignments. - `subject_id`: The user identifier, here foo@bar.baz
. This format matches the examples and conventions shown in the Ory Keto documentation for assigning users to roles or groups [Role Based Access Control (RBAC)](https://www.ory.sh/docs/keto/guides/rbac), [Relationships](https://www.ory.sh/docs/keto/concepts/relation-tuples).