<@U04UQ68083H> how to implement totp with go sdk?
# ory-copilot
f
@chilly-king-10285 how to implement totp with go sdk?
b
A message from kapa.ai
To implement TOTP (Time-based One-Time Password) with the Ory Go SDK, you need to: 1. Enable TOTP in your Ory project configuration Make sure TOTP is enabled in your Ory Identities (Kratos) configuration. You can do this via the Ory Console or by updating your config file:
Copy code
yaml    selfservice:      methods:        totp:          config:            issuer: <http://ExampleIssuer.com|ExampleIssuer.com>          enabled: true
[How to enable TOTP](https://www.ory.sh/docs/kratos/mfa/totp#enabling-totp-authentication) 2. Let users pair their TOTP app Users must go to their account settings and pair their account with a TOTP app (like Google Authenticator). This is typically done through the Ory Account Experience UI, but you can also build your own UI using the SDK and API. 3. Update the settings flow to add TOTP In your Go application, use the Ory Go SDK to update the settings flow and add TOTP for the user. Here’s a code snippet for interacting with the Admin API (for reference):
Copy code
go    import (     "context"     ory "<http://github.com/ory/client-go|github.com/ory/client-go>"    )     client := ory.NewAPIClient(ory.NewConfiguration())     // Example: Update settings flow with TOTP    flowId := "your-settings-flow-id"    totpCode := "123456" // The code from the user's authenticator app     body := map[string]interface{}{     "method":    "totp",     "totp_code": totpCode,    }     resp, _, err := client.FrontendApi.UpdateSettingsFlow(context.Background(), flowId).Body(body).Execute()    if err != nil {     // Handle error    }    // resp contains the updated flow
The request body must include
"method": "totp"
and the TOTP code from the user. You may also need to provide a CSRF token if using browser flows. [API reference for updating settings flow with TOTP](https://www.ory.sh/docs/kratos/reference/api#updateSettingsFlow) 4. Login with TOTP When logging in, after the user provides their primary credentials, prompt for the TOTP code and submit it as part of the login flow:
Copy code
go    body := map[string]interface{}{     "method":    "totp",     "totp_code": totpCode,    }    resp, _, err := client.FrontendApi.UpdateLoginFlow(context.Background(), flowId).Body(body).Execute()
[API reference for updating login flow with TOTP](https://www.ory.sh/docs/kratos/reference/api#updateLoginFlow) Note: - The Go SDK uses the OpenAPI-generated client, so you interact with flows by creating or updating them and passing the required fields. - Users must first pair their TOTP app before they can use TOTP for login. For more details and configuration options, see the official documentation: [Ory Kratos TOTP MFA](https://www.ory.sh/docs/kratos/mfa/totp) [Ory Go SDK reference](https://www.ory.sh/docs/kratos/sdk/go)
f
@chilly-king-10285 how can i show totp seperatly for UI
b
A message from kapa.ai
To show the TOTP setup information (such as the QR code or secret key) separately in your UI, you should use the Ory Kratos settings flow. When a user initiates the settings flow to enable TOTP, the API response will include the necessary information for pairing a TOTP app. Specifically, the response from the settings flow (using the GetSettingsFlow endpoint) will contain UI nodes. For TOTP, you will find a node of type text in the group totp, which includes the secret key and, if configured, a QR code in base64 format. You can extract this information from the response and display it in your UI as you wish. Here is an example of what the TOTP secret node might look like in the API response:
Copy code
json {   "type": "text",   "group": "totp",   "attributes": {     "text": {       "id": 1050006,       "text": "GLAS5YHAJ6V5LT3N7AU2R4AWU6SYOCHS",       "type": "info",       "context": {         "secret": "GLAS5YHAJ6V5LT3N7AU2R4AWU6SYOCHS"       }     },     "id": "totp_secret_key",     "node_type": "text"   },   "messages": [],   "meta": {     "label": {       "id": 1050006,       "text": "This is your authenticator app secret. Use it if you can not scan the QR code.",       "type": "info"     }   } }
If a QR code is available, it will also be included in the nodes, typically as a base64-encoded image. You can render this in your UI by extracting the image data and displaying it in an
<img>
tag. Summary of steps: 1. Start a settings flow for the user. 2. Parse the response for TOTP-related nodes. 3. Display the secret and/or QR code in your UI. This approach allows you to show the TOTP setup information separately and style it as needed in your application UI, independent of the default Ory Account Experience interface. For more details and examples, see the documentation on [UI nodes and TOTP](https://www.ory.sh/docs/kratos/concepts/ui-user-interface#ui-text-nodes) and [TOTP setup](https://www.ory.sh/docs/kratos/mfa/totp#identity-credentials) in Ory Kratos.
f
@chilly-king-10285 root@corteza: ~/ory-hydra-with-kratos-idp/go-part 20250607-120858]\ $ go run main.go Error when calling `FrontendApi.GetSettingsFlow`: Get "/admin/self-service/settings/flows?id=071403f2-85a1-4fc0-8ab0-94bcaab7a9ff": stopped after 10 redirects Full HTTP response: &{307 Temporary Redirect 307 HTTP/1.1 1 1 map[Connection:[keep-alive] Content-Length:[110] Content-Type:[text/html; charset=utf-8] Date:[Sat, 07 Jun 2025 121217 GMT] Location:[/admin/self-service/settings/flows?id=071403f2-85a1-4fc0-8ab0-94bcaab7a9ff] Server:[nginx/1.27.1]] 0x400012e480 110 [] false false map[] 0x4000456500 0x4000407380} settings: <nil> Created identity with ID: 9bb8238a-a95e-40ce-998a-5c7cde2ff687 Email for identity with id 9bb8238a-a95e-40ce-998a-5c7cde2ff687. Traits map[email:foo@example.com namemap[firstfoo last:bar]] Successfully Removed identity
b
A message from kapa.ai
The error you are seeing:
Copy code
Error when calling `FrontendApi.GetSettingsFlow`: Get "/admin/self-service/settings/flows?id=...": stopped after 10 redirects Full HTTP response: ... 307 Temporary Redirect ... Location:[/admin/self-service/settings/flows?id=...]
indicates that your request to the GetSettingsFlow endpoint is being redirected repeatedly, resulting in a redirect loop. Possible causes and solutions based on Ory documentation: 1. Wrong Endpoint (Admin vs. Public API): The
/admin/self-service/settings/flows
endpoint is for the Admin API, but the settings flow for end-users should be handled via the Public API (typically
/self-service/settings/flows
). Using the wrong endpoint can cause redirect issues, especially if the service is behind a reverse proxy or load balancer. 2. Missing or Incorrect Cookies/Session: The settings flow for browser clients relies on session cookies. If you do not provide the correct session cookie or token, Ory will redirect you to the login page or back to the flow, causing a loop. Make sure you are passing the session cookie or token as required by the API. [See: User and profile settings for server-side browser clients](https://www.ory.sh/docs/kratos/self-service/flows/user-settings#user-and-profile-settings-for-server-side-browser-clients) 3. Incorrect UI URL Configuration: If the
selfservice.flows.settings.ui_url
is not set correctly, Ory may not know where to redirect the user, which can also result in redirect loops. [See: Settings UI configuration](https://www.ory.sh/docs/kratos/fallback/settings) 4. Redirect Configuration Issues: If your redirect URLs are not properly configured or whitelisted, Ory may not be able to complete the flow and will keep redirecting. [See: Browser redirects and flow completion](https://www.ory.sh/docs/kratos/concepts/browser-redirect-flow-completion) What you should check: - Make sure you are using the correct (public) endpoint for the settings flow:
/self-service/settings/flows
. - Ensure you are passing the required session cookie or token with your request. - Verify your
ui_url
and allowed return URLs are set correctly in your Ory configuration. - If you are running behind a reverse proxy, ensure headers and paths are forwarded correctly. If you continue to see this issue after checking the above, please provide more details about your configuration and how you are making the request. --- References: - [User and profile settings for server-side browser clients](https://www.ory.sh/docs/kratos/self-service/flows/user-settings#user-and-profile-settings-for-server-side-browser-clients) - [Settings UI configuration](https://www.ory.sh/docs/kratos/fallback/settings) - [Browser redirects and flow completion](https://www.ory.sh/docs/kratos/concepts/browser-redirect-flow-completion)
f
@chilly-king-10285 this is my code where is the problem ? package main import ( "context" "fmt" "os" // hydra "github.com/ory/hydra-client-go" kratos "github.com/ory/kratos-client-go" ) func ptr(s string) *string { return &s } func main() { configuration := kratos.NewConfiguration() configuration.Servers = []kratos.ServerConfiguration{ { URL: "https://kratos.qaap.io/admin", // Kratos Admin API }, } apiClient := kratos.NewAPIClient(configuration) CreateIdentityBody := *kratos.NewCreateIdentityBody( "default", map[string]interface{}{ "email": "foo@example.com", "name": map[string]string{ "first": "foo", "last": "bar", }, }, ) flow_id := "81870a69-d8bc-4fb3-b57a-a408e29afc4c" // Fetch a settings flow (replace "settings-flow-id" with a real flow ID if needed) settings, r, err := apiClient.FrontendAPI.GetSettingsFlow(context.Background()).Id(flow_id).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `FrontendApi.GetSettingsFlow`: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } fmt.Fprintf(os.Stdout, "settings: %v\n", settings) createdIdentity, r, err := apiClient.IdentityAPI.CreateIdentity(context.Background()).CreateIdentityBody(CreateIdentityBody).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `FrontendApi.CreateIdentity``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } // response from `CreateIdentity`: Identity fmt.Fprintf(os.Stdout, "Created identity with ID: %v\n", createdIdentity.Id) getIdentity, r, err := apiClient.IdentityAPI.GetIdentity(context.Background(), createdIdentity.Id).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `FrontendApi.GetIdentity``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } fmt.Fprintf(os.Stdout, "Email for identity with id %v. Traits %v\n", createdIdentity.Id, getIdentity.Traits) r, err = apiClient.IdentityAPI.DeleteIdentity(context.Background(), getIdentity.Id).Execute() if err != nil { fmt.Fprintf(os.Stderr, "Error when calling `FrontendApi.DeleteIdentity``: %v\n", err) fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) } fmt.Println("Successfully Removed identity") // hydraConfig := hydra.NewConfiguration() // hydraConfig.Servers = []hydra.ServerConfiguration{ // { // URL: "https://ory.qaap.io/admin", // Replace with your Hydra Admin API URL // }, // } // hydraClient := hydra.NewAPIClient(hydraConfig) // clientId := "my-client-id-2" // clientSecret := "my-client-secret-2" // clientName := "My Client Name 2" // createOAuth2ClientBody := hydra.OAuth2Client{ // ClientId: &clientId, // ClientSecret: &clientSecret, // ClientName: &clientName, // Scope: ptr("email profile openid offline_access"), // GrantTypes: []string{"authorization_code", "refresh_token"}, // RedirectUris: []string{"https://corteza.qaap.io/auth/external/openid-connect.hydra/callback"}, // ResponseTypes: []string{"code", "token"}, // JwksUri: ptr("https://ory.qaap.io/.well-known/jwks.json"), // TokenEndpointAuthMethod: ptr("client_secret_basic"), // } // oauth2Client, r, err := hydraClient.AdminApi.CreateOAuth2Client(context.Background()).OAuth2Client(createOAuth2ClientBody).Execute() // if err != nil { // fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.CreateOAuth2Client`: %v\n", err) // fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) // } else { // if oauth2Client.ClientId != nil { // fmt.Fprintf(os.Stdout, "Created OAuth2 client with ID: %v\n", *oauth2Client.ClientId) // } else { // fmt.Fprintf(os.Stdout, "Created OAuth2 client with ID: <nil>\n") // } // } }
b
A message from kapa.ai
The main problem in your code is that you are calling the Admin API endpoint (`https://kratos.qaap.io/admin`) for a self-service settings flow, which is intended to be accessed via the Public API endpoint (typically
/self-service/settings/flows
). The Admin API is not designed for browser/self-service flows and will result in redirect loops or errors, as you are experiencing. ### Details from the Knowledge Sources - The [GetSettingsFlow](https://www.ory.sh/docs/kratos/reference/api#getSettingsFlow) endpoint is meant to be accessed via the public API, not the admin API. When using the public API, you must ensure that either the Ory Kratos Session Cookie or the Ory Kratos Session Token are set. - The documentation explicitly states: > You can access this endpoint without credentials when using Ory Kratos' Admin API. However, the self-service flows (like settings, login, registration) are designed for end-user interaction and should be handled via the public endpoints, not the admin endpoints. [See: Get Settings Flow](https://www.ory.sh/docs/kratos/reference/api#getSettingsFlow) - The redirect loop (
stopped after 10 redirects
) is a common symptom when the wrong endpoint is used or when required session information (cookie or token) is missing. [See: User and profile settings for server-side browser clients](https://www.ory.sh/docs/kratos/self-service/flows/user-settings#user-and-profile-settings-for-server-side-browser-clients) ### How to Fix 1. Use the Public API Endpoint for Self-Service Flows Change your configuration to use the public endpoint, for example:
Copy code
go    configuration.Servers = []kratos.ServerConfiguration{        {            URL: "<https://kratos.qaap.io>", // Public API, not /admin        },    }
2. Pass Session Cookie or Token When calling self-service flows, you must provide the session cookie or token. If you are not authenticated, you will be redirected to the login flow, causing a loop. 3. Admin API is for Administrative Actions Creating, getting, and deleting identities should use the Admin API (
/admin
), but self-service flows (settings, login, registration) should use the public API. ### Example Correction
Copy code
go configuration := kratos.NewConfiguration() configuration.Servers = []kratos.ServerConfiguration{     {         URL: "<https://kratos.qaap.io>", // Use public endpoint for self-service flows     }, } apiClient := kratos.NewAPIClient(configuration)  // For GetSettingsFlow, ensure you pass the session cookie or token if required settings, r, err := apiClient.FrontendAPI.GetSettingsFlow(context.Background()).Id(flow_id).Execute()
Summary: - Use the public API endpoint for self-service flows. - Use the admin API endpoint only for administrative actions (like creating identities). - Always provide the required session information for self-service flows. For more details, see the official documentation on [Get Settings Flow](https://www.ory.sh/docs/kratos/reference/api#getSettingsFlow) and [User and profile settings for server-side browser clients](https://www.ory.sh/docs/kratos/self-service/flows/user-settings#user-and-profile-settings-for-server-side-browser-clients).