<@U04UQ68083H> im setting up a local dev setup of ...
# ory-copilot
b
@chilly-king-10285 im setting up a local dev setup of kratos and kratos-selfservice-ui-node and im getting ERR_TOO_MANY_REDIRECTS on multiple pages
b
A message from kapa.ai
Based on the information provided in the knowledge sources, it appears you're experiencing a common issue when setting up Ory Kratos and the self-service UI locally. The ERR_TOO_MANY_REDIRECTS error often occurs due to misconfiguration, especially related to URLs and CORS settings. Here are some steps you can take to troubleshoot: 1. Check your URL configurations: Make sure that your
kratosPublicUrl
and
kratosBrowserUrl
are pointing to the same URL. As mentioned in the [GitHub discussion](https://github.com/ory/kratos/discussions/3695), one user resolved the issue by setting both to the same URL:
Copy code
kratosPublicUrl: <https://dev-server.local.net/kratos>    kratosBrowserUrl: <https://dev-server.local.net/kratos>
2. Verify CORS settings: Ensure that your CORS configuration in Kratos allows the origin of your self-service UI. In the Helm configuration example provided, we can see a CORS setup like this:
Copy code
yaml    cors:        enabled: true        allowed_origins:            - <https://dev-server.local.net/kratos-ui/>            - <http://dev-server.local.net/kratos-ui/>
Make sure your UI's origin is listed in the allowed origins. 3. Check cookie settings: If you're running over HTTP locally, make sure to use the
--dev
flag when starting Kratos. This disables the
Secure
flag on cookies, which is necessary for HTTP. As mentioned in the [CSRF troubleshooting docs](https://www.ory.sh/docs/kratos/debug/csrf):
Copy code
kratos serve --dev
However, remember not to use this in production. 4. Consistent domain usage: Ensure you're using either
localhost
or
127.0.0.1
consistently across your configuration. Mixing these can cause issues as they're treated as separate domains. 5. Check for outdated SDK versions: If you're using an SDK, make sure it's up to date. As mentioned in the [GitHub issue comments](https://github.com/ory/network/issues/124), using an outdated SDK version can cause issues with redirects. If you're still experiencing issues after checking these points, you may need to review your entire configuration for any inconsistencies or seek further assistance from the Ory community.
b
@chilly-king-10285 write me a docker compose for using kratos and kratos-selfservice-ui-node
b
A message from kapa.ai
Certainly! I can provide you with a Docker Compose configuration for setting up Ory Kratos and the Kratos Self-Service UI Node. This configuration is based on the information from the Ory Kratos documentation. Here's a Docker Compose file that should help you get started:
Copy code
yaml version: '3.7'  services:   kratos:     image: oryd/kratos:v0.13.0     ports:       - "4433:4433" # public       - "4434:4434" # admin     environment:       - DSN=memory       - LOG_LEVEL=debug       - SERVE_PUBLIC_BASE_URL=<http://127.0.0.1:4433/>       - SERVE_ADMIN_BASE_URL=<http://kratos:4434/>       - SELFSERVICE_DEFAULT_BROWSER_RETURN_URL=<http://127.0.0.1:4455/>     volumes:       - type: bind         source: ./kratos         target: /etc/config/kratos     command: serve -c /etc/config/kratos/kratos.yml --dev --watch-courier     networks:       - intranet    kratos-selfservice-ui-node:     image: oryd/kratos-selfservice-ui-node:latest     ports:       - "4455:3000"     environment:       - KRATOS_PUBLIC_URL=<http://kratos:4433/>       - KRATOS_BROWSER_URL=<http://127.0.0.1:4433/>     networks:       - intranet     depends_on:       - kratos    mailslurper:     image: oryd/mailslurper:latest-smtps     ports:       - "4436:4436"       - "4437:4437"     networks:       - intranet  networks:   intranet:
This Docker Compose file is based on the configuration provided in the [Ory Kratos Quickstart documentation](https://www.ory.sh/docs/kratos/quickstart#clone-ory-kratos-and-run-it-in-docker). Here's a breakdown of what this configuration does: 1. It sets up three services:
kratos
,
kratos-selfservice-ui-node
, and
mailslurper
. 2. The
kratos
service uses the official Ory Kratos image and exposes the public API on port 4433 and the admin API on port 4434. It's configured to use an in-memory database for simplicity. 3. The
kratos-selfservice-ui-node
service uses the official Kratos Self-Service UI Node image and exposes the UI on port 4455. 4. The
mailslurper
service is included to handle email sending for development purposes. 5. All services are connected to an internal Docker network called
intranet
. To use this configuration: 1. Save the above YAML content in a file named
docker-compose.yml
. 2. Create a
kratos
directory in the same location as your
docker-compose.yml
file. 3. In the
kratos
directory, you'll need to add your Kratos configuration files, including
kratos.yml
and
identity.schema.json
. Then, you can start the services by running:
Copy code
docker-compose up
Remember to adjust the configuration as needed for your specific setup, especially the URLs and ports if you're not running on localhost. [Ory Kratos Quickstart](https://www.ory.sh/docs/kratos/quickstart#clone-ory-kratos-and-run-it-in-docker) provides more detailed information on setting up and configuring Kratos.
b
@chilly-king-10285 give me an example kratos config in json format which will work with your docker-compose
b
A message from kapa.ai
Certainly! I'll provide you with an example Kratos configuration in JSON format that should work with the Docker Compose setup I provided earlier. This configuration is based on the YAML configuration from the [Ory Kratos Quickstart documentation](https://www.ory.sh/docs/kratos/quickstart#clone-ory-kratos-and-run-it-in-docker). Here's an example
kratos.json
file:
Copy code
json
{
  "version": "v0.13.0",
  "dsn": "memory",
  "serve": {
    "public": {
      "base_url": "<http://127.0.0.1:4433/>",
      "cors": {
        "enabled": true
      }
    },
    "admin": {
      "base_url": "<http://kratos:4434/>"
    }
  },
  "selfservice": {
    "default_browser_return_url": "<http://127.0.0.1:4455/>",
    "allowed_return_urls": [
      "<http://127.0.0.1:4455>"
    ],
    "methods": {
      "password": {
        "enabled": true
      },
      "totp": {
        "config": {
          "issuer": "Kratos"
        },
        "enabled": true
      },
      "lookup_secret": {
        "enabled": true
      },
      "link": {
        "enabled": true
      },
      "code": {
        "enabled": true
      }
    },
    "flows": {
      "error": {
        "ui_url": "<http://127.0.0.1:4455/error>"
      },
      "settings": {
        "ui_url": "<http://127.0.0.1:4455/settings>",
        "privileged_session_max_age": "15m",
        "required_aal": "highest_available"
      },
      "recovery": {
        "enabled": true,
        "ui_url": "<http://127.0.0.1:4455/recovery>",
        "use": "code"
      },
      "verification": {
        "enabled": true,
        "ui_url": "<http://127.0.0.1:4455/verification>",
        "use": "code",
        "after": {
          "default_browser_return_url": "<http://127.0.0.1:4455/>"
        }
      },
      "logout": {
        "after": {
          "default_browser_return_url": "<http://127.0.0.1:4455/login>"
        }
      },
      "login": {
        "ui_url": "<http://127.0.0.1:4455/login>",
        "lifespan": "10m"
      },
      "registration": {
        "lifespan": "10m",
        "ui_url": "<http://127.0.0.1:4455/registration>",
        "after": {
          "password": {
            "hooks": [
              {
                "hook": "session"
              },
              {
                "hook": "show_verification_ui"
              }
            ]
          }
        }
      }
    }
  },
  "log": {
    "level": "debug",
    "format": "text",
    "leak_sensitive_values": true
  },
  "secrets": {
    "cookie": [
      "PLEASE-CHANGE-ME-I-AM-VERY-INSECURE"
    ],
    "cipher": [
      "32-LONG-SECRET-NOT-SECURE-AT-ALL"
    ]
  },
  "ciphers": {
    "algorithm": "xchacha20-poly1305"
  },
  "hashers": {
    "algorithm": "bcrypt",
    "bcrypt": {
      "cost": 8
    }
  },
  "identity": {
    "default_schema_id": "default",
    "schemas": [
      {
        "id": "default",
        "url": "file:///etc/config/kratos/identity.schema.json"
      }
    ]
  }
}
To use this configuration:
Certainly! I'll provide you with an example Kratos configuration in JSON format that should work with the Docker Compose setup I provided earlier. This configuration is based on the YAML configuration from the [Ory Kratos Quickstart documentation](https://www.ory.sh/docs/kratos/quickstart#clone-ory-kratos-and-run-it-in-docker). Here's an example
kratos.json
file:
Copy code
json {   "version": "v0.13.0",   "dsn": "memory",   "serve": {     "public": {       "base_url": "<http://127.0.0.1:4433/>",       "cors": {         "enabled": true       }     },     "admin": {       "base_url": "<http://kratos:4434/>"     }   },   "selfservice": {     "default_browser_return_url": "<http://127.0.0.1:4455/>",     "allowed_return_urls": [       "<http://127.0.0.1:4455>"     ],     "methods": {       "password": {         "enabled": true       },       "totp": {         "config": {           "issuer": "Kratos"         },         "enabled": true       },       "lookup_secret": {         "enabled": true       },       "link": {         "enabled": true       },       "code": {         "enabled": true       }     },     "flows": {       "error": {         "ui_url": "<http://127.0.0.1:4455/error>"       },       "settings": {         "ui_url": "<http://127.0.0.1:4455/settings>",         "privileged_session_max_age": "15m",         "required_aal": "highest_available"       },       "recovery": {         "enabled": true,         "ui_url": "<http://127.0.0.1:4455/recovery>",         "use": "code"       },       "verification": {         "enabled": true,         "ui_url": "<http://127.0.0.1:4455/verification>",         "use": "code",         "after": {           "default_browser_return_url": "<http://127.0.0.1:4455/>"         }       },       "logout": {         "after": {           "default_browser_return_url": "<http://127.0.0.1:4455/login>"         }       },       "login": {         "ui_url": "<http://127.0.0.1:4455/login>",         "lifespan": "10m"       },       "registration": {         "lifespan": "10m",         "ui_url": "<http://127.0.0.1:4455/registration>",         "after": {           "password": {             "hooks": [               {                 "hook": "session"               },               {                 "hook": "show_verification_ui"               }             ]           }         }       }     }   },   "log": {     "level": "debug",     "format": "text",     "leak_sensitive_values": true   },   "secrets": {     "cookie": [       "PLEASE-CHANGE-ME-I-AM-VERY-INSECURE"     ],     "cipher": [       "32-LONG-SECRET-NOT-SECURE-AT-ALL"     ]   },   "ciphers": {     "algorithm": "xchacha20-poly1305"   },   "hashers": {     "algorithm": "bcrypt",     "bcrypt": {       "cost": 8     }   },   "identity": {     "default_schema_id": "default",     "schemas": [       {         "id": "default",         "url": "file:///etc/config/kratos/identity.schema.json"       }     ]   } }
To use this configuration: 1. Save this JSON content in a file named
kratos.json
in the
kratos
directory you created earlier (the one that's mounted as a volume in the Docker Compose file). 2. In your Docker Compose file, update the
kratos
service command to use the JSON file:
Copy code
yaml    command: serve -c /etc/config/kratos/kratos.json --dev --watch-courier
3. Make sure you also have an
identity.schema.json
file in the same
kratos
directory. This file defines the structure of your identity objects. This configuration sets up Kratos to use in-memory storage, enables various self-service flows (login, registration, recovery, etc.), and configures the URLs to match the Docker Compose setup. Remember to replace the placeholder secrets (
PLEASE-CHANGE-ME-I-AM-VERY-INSECURE
and
32-LONG-SECRET-NOT-SECURE-AT-ALL
) with your own secure secrets in a production environment. Also, note that this configuration is set up for a local development environment. For a production setup, you would need to make several changes, such as using a persistent database instead of in-memory storage, configuring proper secrets, and setting up HTTPS. [Ory Kratos Configuration Reference](https://www.ory.sh/docs/kratos/reference/configuration) provides more detailed information on all available configuration options.
b
@chilly-king-10285 im creating an oauth2 client using the
ory create oauth2-client
cli, how can i put an additional claim in the access tokens, it will have a static value
b
A message from kapa.ai
To add an additional claim with a static value to the access tokens for an OAuth2 client created using the
ory create oauth2-client
CLI command, you'll need to follow a few steps. This process involves creating the client, then setting up a custom consent UI or using OAuth2 webhooks to add the custom claim. 1. First, create your OAuth2 client using the CLI command:
Copy code
ory create oauth2-client --project $project_id \     --name "Your Client Name" \     --grant-type authorization_code,client_credentials \     --response-type code \     --scope openid,offline
2. After creating the client, you have two main options to add a custom claim to the access token: a. Use a custom consent UI b. Set up an OAuth2 webhook For this example, let's use the OAuth2 webhook method as it's more straightforward for adding a static claim. 3. Set up an OAuth2 webhook: Use the Ory CLI to configure the webhook:
Copy code
ory patch oauth2-config --project <project-id> --workspace <workspace-id> \ --add '/oauth2/token_hook="<https://your-webhook-endpoint.com/token-hook>"' \ --format yaml
Replace
<https://your-webhook-endpoint.com/token-hook>
with the actual URL of your webhook endpoint. 4. Implement the webhook endpoint: Your webhook should respond with a JSON payload that includes the custom claim. Here's an example of how your webhook response should look:
Copy code
json {   "session": {     "access_token": {       "your_custom_claim": "static_value"     }   } }
5. Configure allowed top-level claims: To add your custom claim at the top level of the access token, you need to configure the allowed top-level claims:
Copy code
ory patch oauth2-config --project <project-id> --workspace <workspace-id> \   --replace "/oauth2/allowed_top_level_claims=[\"your_custom_claim\"]"
This step allows your custom claim to be included at the top level of the access token. After setting up the webhook and configuring the allowed top-level claims, the access tokens issued for your OAuth2 client will include the custom claim with the static value you specified. The resulting access token structure will look something like this:
Copy code
json {   "sub": "...",   "your_custom_claim": "static_value",   "ext": {     "your_custom_claim": "static_value"   }   // ... other standard claims }
Remember that this setup requires you to have a webhook endpoint that can handle the token customization requests. If you don't want to set up a webhook, you would need to implement a custom consent UI, which is a more complex process. For more detailed information on customizing claims and using OAuth2 webhooks, you can refer to the [Ory documentation on customizing claims with OAuth2 webhooks](https://www.ory.sh/docs/hydra/guides/claims-at-refresh).
b
@chilly-king-10285 implement a simple oauth2 webhook in golang, use the ory sdk if required (struct definitions)
b
A message from kapa.ai
Certainly! I'll provide you with a simple OAuth2 webhook implementation in Go, using the Ory SDK for struct definitions. This webhook will add a custom claim to the access token. Here's an example implementation:
Copy code
go
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"

	ory "<http://github.com/ory/client-go|github.com/ory/client-go>"
)

type WebhookResponse struct {
	Session struct {
		AccessToken map[string]interface{} `json:"access_token"`
	} `json:"session"`
}

func tokenHookHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Only POST method is allowed", http.StatusMethodNotAllowed)
		return
	}

	var webhookPayload ory.TokenHookRequest
	err := json.NewDecoder(r.Body).Decode(&webhookPayload)
	if err != nil {
		http.Error(w, "Invalid JSON input", http.StatusBadRequest)
		return
	}

	// Log the received payload for debugging
	log.Printf("Received webhook payload: %+v\n", webhookPayload)

	// Prepare the response with the custom claim
	response := WebhookResponse{}
	response.Session.AccessToken = map[string]interface{}{
		"custom_claim": "static_value",
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

func main() {
	http.HandleFunc("/token-hook", tokenHookHandler)

	fmt.Println("Starting webhook server on :8080...")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatalf("Server failed to start: %v", err)
	}
}
This implementation does the following: 1. We import the necessary packages, including the Ory SDK (`github.com/ory/client-go`). 2. We define a
WebhookResponse
struct that matches the expected response format for the OAuth2 webhook. 3. The
tokenHookHandler
function handles the webhook requests: - It checks if the request method is POST. - It decodes the incoming JSON payload into an
ory.TokenHookRequest
struct, which is provided by the Ory SDK. - It logs the received payload for debugging purposes. - It prepares a response with a custom claim (
custom_claim
) set to a static value (
static_value
). - It sends the response back as JSON. 4. In the
main
function, we set up an HTTP server that listens on port 8080 and registers the
/token-hook
endpoint. To use this webhook: 1. Make sure you have the Ory SDK installed:
Copy code
go get <http://github.com/ory/client-go|github.com/ory/client-go>
2. Save the code in a file (e.g.,
webhook.go
). 3. Run the webhook server:
Copy code
go run webhook.go
4. Configure Ory to use this webhook (assuming you're running it locally):
Copy code
ory patch oauth2-config --project <project-id> --workspace <workspace-id> \
   --add '/oauth2/token_hook="<http://localhost:8080/token-hook>"' \
   --format yaml
5. Don't forget to configure the allowed top-level claims as mentioned in the previous answer:
Copy code
ory patch oauth2-config --project <project-id> --workspace <workspace-id> \
   --replace "/oauth2/allowed_top_level_claims=[\"custom_claim\"]"
Certainly! I'll provide you with a simple OAuth2 webhook implementation in Go, using the Ory SDK for struct definitions. This webhook will add a custom claim to the access token. Here's an example implementation:
Copy code
go package main  import (  "encoding/json"  "fmt"  "log"  "net/http"   ory "<http://github.com/ory/client-go|github.com/ory/client-go>" )  type WebhookResponse struct {  Session struct {   AccessToken map[string]interface{} `json:"access_token"`  } `json:"session"` }  func tokenHookHandler(w http.ResponseWriter, r *http.Request) {  if r.Method != http.MethodPost {   http.Error(w, "Only POST method is allowed", http.StatusMethodNotAllowed)   return  }   var webhookPayload ory.TokenHookRequest  err := json.NewDecoder(r.Body).Decode(&webhookPayload)  if err != nil {   http.Error(w, "Invalid JSON input", http.StatusBadRequest)   return  }   // Log the received payload for debugging  log.Printf("Received webhook payload: %+v\n", webhookPayload)   // Prepare the response with the custom claim  response := WebhookResponse{}  response.Session.AccessToken = map[string]interface{}{   "custom_claim": "static_value",  }   w.Header().Set("Content-Type", "application/json")  json.NewEncoder(w).Encode(response) }  func main() {  http.HandleFunc("/token-hook", tokenHookHandler)   fmt.Println("Starting webhook server on :8080...")  if err := http.ListenAndServe(":8080", nil); err != nil {   log.Fatalf("Server failed to start: %v", err)  } }
This implementation does the following: 1. We import the necessary packages, including the Ory SDK (`github.com/ory/client-go`). 2. We define a
WebhookResponse
struct that matches the expected response format for the OAuth2 webhook. 3. The
tokenHookHandler
function handles the webhook requests: - It checks if the request method is POST. - It decodes the incoming JSON payload into an
ory.TokenHookRequest
struct, which is provided by the Ory SDK. - It logs the received payload for debugging purposes. - It prepares a response with a custom claim (
custom_claim
) set to a static value (
static_value
). - It sends the response back as JSON. 4. In the
main
function, we set up an HTTP server that listens on port 8080 and registers the
/token-hook
endpoint. To use this webhook: 1. Make sure you have the Ory SDK installed:
Copy code
go get <http://github.com/ory/client-go|github.com/ory/client-go>
2. Save the code in a file (e.g.,
webhook.go
). 3. Run the webhook server:
Copy code
go run webhook.go
4. Configure Ory to use this webhook (assuming you're running it locally):
Copy code
ory patch oauth2-config --project <project-id> --workspace <workspace-id> \    --add '/oauth2/token_hook="<http://localhost:8080/token-hook>"' \    --format yaml
5. Don't forget to configure the allowed top-level claims as mentioned in the previous answer:
Copy code
ory patch oauth2-config --project <project-id> --workspace <workspace-id> \    --replace "/oauth2/allowed_top_level_claims=[\"custom_claim\"]"
This webhook will add a
custom_claim
with the value
static_value
to every access token issued. You can modify the
tokenHookHandler
function to add more complex logic or dynamic values as needed. Remember to handle errors appropriately and add proper authentication to your webhook in a production environment. The [Ory documentation on customizing claims with OAuth2 webhooks](https://www.ory.sh/docs/hydra/guides/claims-at-refresh) provides more information on secure webhook implementation.
b
@chilly-king-10285 can i add additional claims without using a webhook?
b
A message from kapa.ai
Yes, you can add additional claims to OAuth2 tokens without using a webhook. Ory provides a way to add custom claims directly during the consent process. This can be done using a custom consent UI or by modifying the consent request when accepting it. According to the [Ory documentation on custom consent UI and custom claims for JWT access tokens](https://www.ory.sh/docs/oauth2-oidc/jwt-access-token#custom-consent-ui-and-custom-claims-for-jwt-access-token), you can add custom claims to every access token during consent acceptance. Here's how you can do it: 1. When accepting the consent request, you can add custom claims to the access token and ID token:
Copy code
javascript
import { Configuration, OAuth2Api } from "@ory/client"

const ory = new OAuth2Api(
  new Configuration({
    basePath: `https://${process.env.ORY_PROJECT_SLUG}.<http://projects.oryapis.com|projects.oryapis.com>`,
    accessToken: process.env.ORY_API_KEY,
  }),
)

export async function acceptConsent(consentChallenge: string) {
  const { data } = await ory.getOAuth2ConsentRequest({ consentChallenge })

  return await ory
    .acceptOAuth2ConsentRequest({
      consentChallenge: consentChallenge,
      acceptOAuth2ConsentRequest: {
        session: {
          access_token: {
            some_custom_claim: "some_custom_value",
          },
          id_token: {
            id_custom_claim: "some_value",
          },
        },
      },
    })
    .then(({ data }) => data)
}
2. This will result in an access token with the following structure:
Copy code
json
{
  "sub": "...",
  // ...
  "ext": {
    "some_custom_claim": "some_custom_value",
  },
  // ...
}
3. If you want the custom claim to be at the top level of the access token instead of nested under "ext", you need to modify the
/oauth2/allowed_top_level_claims
configuration:
Copy code
ory patch oauth2-config --project <project-id> --workspace <workspace-id> \
  --replace "/oauth2/allowed_top_level_claims=[\"some_custom_claim\"]"
This will result in an access token with the following structure:
Copy code
json
{
  "sub": "...",
  // ...
  "some_custom_claim": "some_custom_value",
  "ext": {
    "some_custom_claim": "some_custom_value"
  }
  // ...
}
4. If you don't want to mirror the claims under the "ext" claim, you can disable this behavior:
Copy code
ory patch oauth2-config --project <project-id> --workspace <workspace-id> \
  --replace "/oauth2/mirror_top_level_claims=false"
This approach allows you to add custom claims without setting up a separate webhook. However, keep in mind that this method requires you to implement a custom consent flow or modify your existing consent acceptance logic. [Custom consent UI and custom claims for JWT access token](https://www.ory.sh/docs/oauth2-oidc/jwt-access-token#custom-consent-ui-and-custom-claims-for-jwt-access-token)
Yes, you can add additional claims to OAuth2 tokens without using a webhook. Ory provides a way to add custom claims directly during the consent process. This can be done using a custom consent UI or by modifying the consent request when accepting it. According to the [Ory documentation on custom consent UI and custom claims for JWT access tokens](https://www.ory.sh/docs/oauth2-oidc/jwt-access-token#custom-consent-ui-and-custom-claims-for-jwt-access-token), you can add custom claims to every access token during consent acceptance. Here's how you can do it: 1. When accepting the consent request, you can add custom claims to the access token and ID token:
Copy code
javascript import { Configuration, OAuth2Api } from "@ory/client"  const ory = new OAuth2Api(   new Configuration({     basePath: `https://${process.env.ORY_PROJECT_SLUG}.<http://projects.oryapis.com|projects.oryapis.com>`,     accessToken: process.env.ORY_API_KEY,   }), )  export async function acceptConsent(consentChallenge: string) {   const { data } = await ory.getOAuth2ConsentRequest({ consentChallenge })    return await ory     .acceptOAuth2ConsentRequest({       consentChallenge: consentChallenge,       acceptOAuth2ConsentRequest: {         session: {           access_token: {             some_custom_claim: "some_custom_value",           },           id_token: {             id_custom_claim: "some_value",           },         },       },     })     .then(({ data }) => data) }
2. This will result in an access token with the following structure:
Copy code
json {   "sub": "...",   // ...   "ext": {     "some_custom_claim": "some_custom_value",   },   // ... }
3. If you want the custom claim to be at the top level of the access token instead of nested under "ext", you need to modify the
/oauth2/allowed_top_level_claims
configuration:
Copy code
ory patch oauth2-config --project <project-id> --workspace <workspace-id> \   --replace "/oauth2/allowed_top_level_claims=[\"some_custom_claim\"]"
This will result in an access token with the following structure:
Copy code
json {   "sub": "...",   // ...   "some_custom_claim": "some_custom_value",   "ext": {     "some_custom_claim": "some_custom_value"   }   // ... }
4. If you don't want to mirror the claims under the "ext" claim, you can disable this behavior:
Copy code
ory patch oauth2-config --project <project-id> --workspace <workspace-id> \   --replace "/oauth2/mirror_top_level_claims=false"
This approach allows you to add custom claims without setting up a separate webhook. However, keep in mind that this method requires you to implement a custom consent flow or modify your existing consent acceptance logic. [Custom consent UI and custom claims for JWT access token](https://www.ory.sh/docs/oauth2-oidc/jwt-access-token#custom-consent-ui-and-custom-claims-for-jwt-access-token) Remember that this method gives you control over the claims at the time of consent, which might be suitable for dynamic values. For completely static values, the webhook method we discussed earlier might still be more convenient as it doesn't require modifying the consent flow.
b
@chilly-king-10285 I am using client credential flow for machine to machine auth, can i still add an additional claim without using a webhook?
b
A message from kapa.ai
Based on the information provided in the knowledge sources, it appears that adding custom claims to access tokens in the client credentials flow without using a webhook is not directly supported by Ory. The client credentials flow is designed for machine-to-machine authentication and doesn't involve a user consent step, which is where custom claims are typically added in other flows. As described in the [OAuth2 Client Credentials Flow documentation](https://www.ory.sh/docs/oauth2-oidc/client-credentials), this flow is straightforward and doesn't include a mechanism for adding custom claims during the token issuance process. The primary methods for adding custom claims that are mentioned in the documentation are: 1. Using OAuth2 webhooks, as described in the [Customizing claims with OAuth2 webhooks guide](https://www.ory.sh/docs/hydra/guides/claims-at-refresh). 2. Adding claims during the consent process, which is not applicable to the client credentials flow. Given these limitations, if you need to add custom claims to access tokens in the client credentials flow, the most reliable method would be to use a webhook. The webhook allows you to modify the token before it's issued, regardless of the grant type being used. If using a webhook is not an option for your use case, you might need to consider alternative approaches or reach out to Ory support for more specific guidance on whether there are any undocumented methods to achieve this in the client credentials flow.