wooden-manchester-52124
02/27/2025, 3:45 PMbrief-egg-61061
02/27/2025, 3:45 PMbrief-egg-61061
02/27/2025, 3:46 PMPOST /admin/identities
- GET /admin/identities
- GET /admin/identities/{id}
- PUT /admin/identities/{id}
These endpoints require an API key for authorization, ensuring that only admins can access and modify the data. For more information on managing identity metadata and traits, you can refer to the [Identity metadata & traits](https://www.ory.sh/docs/kratos/manage-identities/managing-users-identities-metadata) documentation. Remember that while traits are validated against the identity's JSON schema, metadata is not. You'll need to ensure the validity of the metadata you store according to your own schema. [Identity metadata & traits](https://www.ory.sh/docs/kratos/manage-identities/managing-users-identities-metadata) provides more detailed information on this topic.wooden-manchester-52124
02/27/2025, 3:51 PMbrief-egg-61061
02/27/2025, 3:51 PMbrief-egg-61061
02/27/2025, 3:51 PMidentity
field, which contains both metadata_public
and metadata_admin
properties: json { // ... other session properties ... "identity": { // ... other identity properties ... "metadata_admin": {}, "metadata_public": {}, // ... other identity properties ... } }
However, it's important to note that while both fields are present in the structure, the metadata_admin
field will always be empty when accessed through non-admin APIs or in the context of a user session. This behavior ensures that sensitive information stored in admin metadata remains protected and is only accessible through the appropriate admin APIs. For more detailed information about sessions and their content, you can refer to the [Session Management Overview](https://www.ory.sh/docs/kratos/session-management/overview) documentation.wooden-manchester-52124
03/07/2025, 8:47 PMbrief-egg-61061
03/07/2025, 8:47 PMbrief-egg-61061
03/07/2025, 8:47 PM/admin/identities
APIs. They are visible to anyone having access to the user's sessions, for example by calling toSession()
or /sessions/whoami
. This allows you to access the metadata in the frontend without calling the admin APIs." This approach allows you to: - Make the information visible to users (unlike admin metadata which is completely hidden from users) - Prevent users from modifying this information - Allow admins to modify this information using the admin APIs To implement this: 1. Store the read-only information in the metadata_public
field of the identity instead of in the traits
. 2. Use the admin APIs (like PUT /admin/identities/{id}
) to manage this data when it needs to be updated. 3. The information will be available to the user through session information, but they won't be able to modify it through self-service flows. Remember that metadata is not validated against the identity's JSON schema, so you'll need to ensure the validity of the data you store in metadata fields. This approach gives you the flexibility to have some fields that users can modify (stored in traits) and others that are read-only for users but modifiable by admins (stored in public metadata). [Identity metadata & traits](https://www.ory.sh/docs/kratos/manage-identities/managing-users-identities-metadata)wooden-manchester-52124
03/07/2025, 8:55 PMbrief-egg-61061
03/07/2025, 8:55 PMbrief-egg-61061
03/07/2025, 8:55 PMjson { "$id": "<https://example.com/person.schema.json>", "$schema": "<http://json-schema.org/draft-07/schema#>", "title": "Person", "type": "object", "properties": { "traits": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "title": "Email", "<http://ory.sh/kratos|ory.sh/kratos>": { "credentials": { "password": { "identifier": true } } } }, "name": { "type": "object", "properties": { "first": { "type": "string" }, "last": { "type": "string" } } } }, "required": ["email"] } } }
This schema defines the structure for the traits of an identity. Now, let's look at how you might set up an identity with this schema, including admin and public metadata: yaml id: "9f425a8d-7efc-4768-8f23-7647a74fdf13" schema_id: "<https://example.com/person.schema.json>" traits: email: "<mailto:user@example.com|user@example.com>" name: first: "John" last: "Doe" metadata_public: account_type: "premium" signup_date: "2023-06-15" metadata_admin: internal_id: "INT12345" credit_score: 750
In this example: 1. The traits
field contains information that the user can modify (as defined in the schema). 2. The metadata_public
field contains information that the user can see but can't modify. This could be used for things like account type or signup date. 3. The metadata_admin
field contains information that only admins can see and modify. This could be used for internal IDs, credit scores, or other sensitive information. Remember, while traits are validated against the schema, metadata fields are not. You'll need to ensure the validity of metadata separately. To manage metadata, you would use the admin APIs as described in the [Identity metadata & traits](https://www.ory.sh/docs/kratos/manage-identities/managing-users-identities-metadata) documentation. For example, to update the public metadata, you might use a PUT request to /admin/identities/{id}
with a payload that includes the metadata_public
field. This setup allows you to have a mix of user-modifiable data (traits), user-visible but admin-only modifiable data (public metadata), and admin-only visible and modifiable data (admin metadata).wooden-manchester-52124
03/07/2025, 9:07 PMbrief-egg-61061
03/07/2025, 9:07 PMbrief-egg-61061
03/07/2025, 9:07 PMmetadata_public
field in the same way you define schemas for identity traits. The [Identity metadata & traits](https://www.ory.sh/docs/kratos/manage-identities/managing-users-identities-metadata) documentation states: "Metadata is not validated using the identity's JSON schema. You must ensure that the metadata you store is valid according to your schema and you must keep the schema up to date to accommodate changes in the data." This means that while you can define a strict schema for the traits of an identity, the metadata_public
(and metadata_admin
) fields are more flexible and do not adhere to a predefined schema within the Ory system. Instead, you have to manage the structure and validation of metadata fields yourself. This gives you more flexibility in storing various types of data, but it also means you need to be careful about maintaining consistency and validity in these fields. If you need to enforce a specific structure for your metadata, you would need to implement that validation in your own application logic when setting or updating the metadata through the admin APIs. [Identity metadata & traits](https://www.ory.sh/docs/kratos/manage-identities/managing-users-identities-metadata)wooden-manchester-52124
03/26/2025, 8:50 PMbrief-egg-61061
03/26/2025, 8:50 PMbrief-egg-61061
03/26/2025, 8:51 PMsession: whoami: tokenizer: templates: jwt_template_1: jwks_url: base64://... # A JSON Web Key Set (required) claims_mapper_url: base64://... # A JsonNet template for modifying the claims ttl: 1m # 1 minute (defaults to 10 minutes)
As you can see in this configuration example from the [Convert Ory Sessions to JSON Web Tokens](https://www.ory.sh/docs/identities/session-to-jwt-cors#json-web-token-templates) documentation, the ttl
parameter defaults to 10 minutes if not specified. You can customize this TTL value when setting up your JWT template configuration to make the token valid for a longer or shorter period according to your security requirements. It's important to note that this is different from the session lifespan itself, which can be configured separately and might be much longer (for example, the default session lifespan in some configurations is 1 hour).wooden-manchester-52124
03/26/2025, 8:52 PMbrief-egg-61061
03/26/2025, 8:52 PMbrief-egg-61061
03/26/2025, 8:53 PMsession: whoami: tokenizer: templates: jwt_template_1: jwks_url: base64://... # A JSON Web Key Set (required) claims_mapper_url: base64://... # A JsonNet template for modifying the claims ttl: 720h # Match the session lifespan of 30 days
As shown in the [Convert Ory Sessions to JSON Web Tokens](https://www.ory.sh/docs/identities/session-to-jwt-cors#json-web-token-templates) documentation, the TTL parameter can be customized to your needs. The default is 10 minutes if not specified, but you can set it to match your session lifespan. Keep in mind that longer-lived JWTs come with security trade-offs since, unlike session cookies, JWTs cannot be invalidated once issued (until they expire). This is one of the reasons why the default TTL is relatively short. However, if your use case requires matching the session lifespan, you can certainly configure it that way.wooden-manchester-52124
03/26/2025, 8:54 PMbrief-egg-61061
03/26/2025, 8:54 PMbrief-egg-61061
03/26/2025, 8:54 PMwooden-manchester-52124
03/27/2025, 5:17 PMbrief-egg-61061
03/27/2025, 5:17 PMbrief-egg-61061
03/27/2025, 5:17 PMory_
or specifically with patterns like csrf_token_*
or ory_oauth2_*_csrf_*
for OAuth2 flows. These tokens are unique per session/flow and are compared with values submitted in forms to verify legitimate requests. 2. Ory Session Cookie: This cookie (prefixed with ory_session_
) contains the actual session information and is used to maintain the user's authenticated state. According to the [security-compliance documentation](https://www.ory.sh/docs/security-compliance/token-formats), Ory session cookies are prefixed with ory_session_
followed by a project-specific identifier. From the examples in the knowledge sources, we can see that these cookies have different formats and values: Set-Cookie: csrf_token=b8OebRPTPr5ow23mA5gIZmFNLeuMbv8pZz1jT1Ex7ys=; Path=/; Domain=127.0.0.1; Max-Age=31536000; HttpOnly Set-Cookie: ory_kratos_session=MTU5OTE2ODc2N3xEdi1CQkFFQ180SUFBUkFCRUFBQVJfLUNBQUVHYzNSeWFXNW5EQThBRFhObGMzTnBiMjVmZEc5clpXNEdjM1J5YVc1bkRDSUFJR055VlROMGRteHhSakJrUzBkbmRUUjBlVFY1V0RCRWFVTnJXVmR6V25oaHx2DICsB6IMbaHSQwnYITUZqr7Qx7CxUlnaneJWH495wQ==; Path=/; Expires=Fri, 04 Sep 2020 21:32:47 GMT; Max-Age=86400; HttpOnly; SameSite=Lax
Additionally, in OAuth2 flows, the CSRF cookies can have a suffix that is a hash of the OAuth client's ID, as mentioned in the [CSRF name changed in v2.x](https://github.com/ory/hydra/discussions/3801) discussion. This allows for concurrent login sessions for different OAuth clients. There was also a reported issue where users observed multiple CSRF cookies with different suffixes, as seen in the [Double ory_hydra_login_csrf_dev_numsuffix in our cookies](https://github.com/ory/hydra/discussions/3834) discussion. So yes, these values are unique - they serve different purposes and have different formats, with the CSRF token being specifically designed to protect against CSRF attacks while the session cookie maintains the authenticated state.wooden-manchester-52124
03/27/2025, 5:19 PMbrief-egg-61061
03/27/2025, 5:19 PMbrief-egg-61061
03/27/2025, 5:20 PM/sessions/whoami
endpoint, you should use the Ory session cookie as the cache key, not the CSRF token. Here's why: 1. The session cookie (e.g., ory_kratos_session=...
) is what identifies the user's session when making requests to the /sessions/whoami
endpoint. As shown in the documentation, this is the cookie that's used to validate the session: curl -s -H "Cookie: ory_kratos_session=MTU5OTE2ODc2N3xEdi1CQkFFQ180SUFBUkFCRUFBQVJfLUNBQUVHYzNSeWFXNW5EQThBRFhObGMzTnBiMjVmZEc5clpXNEdjM1J5YVc1bkRDSUFJR055VlROMGRteHhSakJrUzBkbmRUUjBlVFY1V0RCRWFVTnJXVmR6V25oaHx2DICsB6IMbaHSQwnYITUZqr7Qx7CxUlnaneJWH495wQ==" \ <https://playground.projects.oryapis.com/sessions/whoami> | jq
2. The CSRF token is used for protecting against cross-site request forgery attacks in form submissions, not for session validation. 3. In a GitHub issue about Oathkeeper hitting rate limits on the /sessions/whoami
endpoint, a user suggested implementing caching based on the session cookie: "I was suggesting to add a cache mechanism based on the session cookie, in order to avoid unnecessary requests to the whoami
endpoint. If the TTL is low (~1s for instance), the security trade-off is acceptable." [Github Issue #1167](https://github.com/ory/oathkeeper/issues/1167) 4. Ory Network itself implements Edge Sessions caching for the /sessions/whoami
endpoint, which uses the session credentials as the cache key: "If the session credentials are known and cached, the cache is served immediately and refreshed in the background." [Low latency with Edge Sessions](https://www.ory.sh/docs/concepts/cache) For your cache implementation: 1. Use the entire Ory session cookie value as your cache key 2. Set a relatively short TTL (e.g., 1-10 seconds) to balance performance with security 3. Consider implementing cache invalidation when users log out or modify their profile This approach will help you stay within the rate limits while maintaining security. The documentation shows that the /sessions/whoami
endpoint has higher rate limits than other endpoints (e.g., 80 requests per second for Production plans), but caching can still be beneficial for high-traffic applications. [Low latency with Edge Sessions](https://www.ory.sh/docs/concepts/cache) [Github Issue #1167](https://github.com/ory/oathkeeper/issues/1167) [Understand Ory Network rate limiting](https://www.ory.sh/docs/guides/rate-limits#project-rate-limits-in-workspaces)wooden-manchester-52124
03/27/2025, 5:24 PMbrief-egg-61061
03/27/2025, 5:24 PMbrief-egg-61061
03/27/2025, 5:25 PMToSession()
. The ToSession()
method is specifically used to check if a user has a valid session, not to verify CSRF tokens. According to the knowledge sources, CSRF token verification happens in a different context - specifically when submitting forms or making POST/PUT/DELETE requests to protected endpoints. The /sessions/whoami
endpoint (which is what ToSession()
calls) is a GET request that only checks for session validity, not CSRF tokens. From the [Kratos Concepts Security documentation](https://www.ory.sh/docs/kratos/concepts/security#defenses-against-cross-site-request-forgery): "The protected APIs are mainly the endpoints that accept the POST
, DELETE
, or PUT
methods. For example, when an app renders a form, a <input type="hidden" name="csrf_token" value="...">
HTML input element is added. Ory Identities compares that value to the value set in the anti-CSRF cookie. If the values match, the request is allowed." In your code snippet: go session, _, err := s.oryClient.Client.FrontendAPI.ToSession(c.Request.Context()). Cookie(cookies). Execute()
This is simply checking if the user has a valid session by passing the cookies to the /sessions/whoami
endpoint. The CSRF verification would happen in other endpoints, particularly when submitting forms like login, registration, or settings flows. If you're looking to implement CSRF protection in your application, you would need to include the CSRF token in your form submissions as shown in the [Debug section of the Custom UI Integration Basics](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#debug) documentation.wooden-manchester-52124
03/27/2025, 5:52 PMbrief-egg-61061
03/27/2025, 5:53 PMbrief-egg-61061
03/27/2025, 5:53 PMfeature_flags.cacheable_sessions: true
in your configuration. Simply setting the TTL without enabling the feature won't have any effect. 2. Cache configuration: The proper configuration requires both enabling the feature and setting the max age: yaml feature_flags: cacheable_sessions: true cacheable_sessions_max_age: "60m"
3. Cache-Control headers: If your application is sending Cache-Control: max-age=0
headers with requests, it will force bypass the cache regardless of your TTL settings. As mentioned in the [Edge Sessions documentation](https://www.ory.sh/docs/concepts/cache#force-refresh): "You can force the /session/whoami
API to bypass the cache and to return a fresh response by setting Cache-Control: max-age=0
." 4. Different rate limits for different endpoints: Make sure you're hitting the rate limits on the /sessions/whoami
endpoint specifically. Different endpoints have different rate limits as shown in the [rate limits documentation](https://www.ory.sh/docs/guides/rate-limits#project-rate-limits-in-workspaces). 5. Client-side caching: If you're using Oathkeeper with the cookie_session
authenticator, consider implementing a client-side cache as suggested in [GitHub issue #1167](https://github.com/ory/oathkeeper/issues/1167). This would cache the session validation results based on the session cookie to reduce calls to the /sessions/whoami
endpoint. To properly implement Edge Sessions caching: 1. Enable the feature and set the TTL using the Ory Console or CLI 2. Ensure your requests aren't bypassing the cache with Cache-Control headers 3. Consider implementing client-side caching if you're using Oathkeeper If you've done all of this and are still hitting rate limits, you might need to consider upgrading your subscription plan for higher limits or reaching out to Ory support for further assistance. [Low latency with Edge Sessions](https://www.ory.sh/docs/concepts/cache) [Understand Ory Network rate limiting](https://www.ory.sh/docs/guides/rate-limits)