famous-jackal-2829
06/08/2025, 4:59 AMbrief-egg-61061
06/08/2025, 4:59 AMbrief-egg-61061
06/08/2025, 5:00 AMgo package frontend import ( "context" "fmt" "os" "<http://github.com/ory/client-go|github.com/ory/client-go>" ) type oryMiddleware struct { ory *ory.APIClient } func init() { cfg := client.NewConfiguration() cfg.Servers = client.ServerConfigurations{ {URL: fmt.Sprintf("<https://%s.projects.oryapis.com>", os.Getenv("ORY_PROJECT_SLUG"))}, } ory = client.NewAPIClient(cfg) } func CreateLogin(ctx context.Context) (*client.LoginFlow, error) { flow, _, err := ory.FrontendApi.CreateNativeLoginFlow(ctx).Execute() if err != nil { return nil, err } return flow, nil }
[See source](https://www.ory.sh/docs/kratos/sdk/go#frontend-api) 2. Render the Login Form Use the data from the login flow (e.g., CSRF token, identifier, password fields) to render your custom login page. The flow response contains all necessary UI nodes for your form fields. [See example response structure](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#create-login-flow) 3. Submit the Login Flow When the user submits the form, send the data to Kratos to complete the login: go func SubmitLogin(ctx context.Context, flowId string, body client.UpdateLoginFlowBody) (*client.SuccessfulNativeLogin, error) { flow, _, err := ory.FrontendApi.UpdateLoginFlow(ctx).Flow(flowId).UpdateLoginFlowBody(body).Execute() if err != nil { return nil, err } return flow, nil }
[See source](https://www.ory.sh/docs/kratos/sdk/go#submit-login-flow) 4. Integrate with Hydra (OIDC) When using Kratos with Hydra, you need to handle the login_challenge
parameter. When Hydra initiates a login, it will redirect to your login UI with a login_challenge
query parameter. Pass this parameter to Kratos when initializing the login flow. Example: GET /self-service/login/browser?login_challenge=abcde
[See documentation](https://www.ory.sh/docs/kratos/reference/api#createbrowserloginflow) After successful login, Kratos will redirect back to Hydra to continue the OIDC flow. Summary of Steps: - Create a login flow (pass login_challenge
if present). - Render the form using the flow data. - Submit the form to Kratos. - On success, handle the redirect back to Hydra. References: - [Ory Kratos Go SDK: Frontend API](https://www.ory.sh/docs/kratos/sdk/go#frontend-api) - [Custom UI Integration: Login Flow](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#create-login-flow) - [Hydra + Kratos OIDC integration](https://www.ory.sh/docs/kratos/reference/api#createbrowserloginflow) If you need a full working example, Ory provides [example applications](https://github.com/ory/kratos-selfservice-ui-node) (in Node.js) that you can adapt to Go. The Go SDK code above shows the main flow for backend integration.famous-jackal-2829
06/08/2025, 5:01 AMbrief-egg-61061
06/08/2025, 5:01 AMbrief-egg-61061
06/08/2025, 5:01 AMlogin_challenge
parameter from Hydra and pass it through your flow. - The actual HTML rendering is not included in the Go code, as Ory expects you to use the flow data to render your own UI. --- go package main import ( "context" "fmt" "html/template" "log" "net/http" "os" "<http://github.com/ory/client-go|github.com/ory/client-go>" ) var ory *client.APIClient func init() { cfg := client.NewConfiguration() cfg.Servers = client.ServerConfigurations{ {URL: fmt.Sprintf("<https://%s.projects.oryapis.com>", os.Getenv("ORY_PROJECT_SLUG"))}, } ory = client.NewAPIClient(cfg) } // Handler to initialize the login flow func handleLogin(w http.ResponseWriter, r *http.Request) { ctx := context.Background() loginChallenge := r.URL.Query().Get("login_challenge") // Create a native login flow, passing login_challenge if present flow, _, err := ory.FrontendApi.CreateNativeLoginFlow(ctx).LoginChallenge(loginChallenge).Execute() if err != nil { http.Error(w, "Failed to create login flow: "+err.Error(), http.StatusInternalServerError) return } // Render the login form using the flow data (simplified) tmpl := template.Must(template.New("login").Parse(` <form action="/login/submit?flow={{.Id}}" method="post"> {{range .Ui.Nodes}} {{if eq .Attributes.Name "csrf_token"}} <input type="hidden" name="csrf_token" value="{{.Attributes.Value}}"> {{end}} {{if eq .Attributes.Name "identifier"}} <label>ID</label> <input type="text" name="identifier" required> {{end}} {{if eq .Attributes.Name "password"}} <label>Password</label> <input type="password" name="password" required> {{end}} {{if eq .Attributes.Name "method"}} <input type="submit" name="method" value="password"> {{end}} {{end}} </form> `)) tmpl.Execute(w, flow) } // Handler to submit the login flow func handleLoginSubmit(w http.ResponseWriter, r *http.Request) { ctx := context.Background() flowId := r.URL.Query().Get("flow") if err := r.ParseForm(); err != nil { http.Error(w, "Invalid form", http.StatusBadRequest) return } body := client.UpdateLoginFlowBody{ Method: "password", CsrfToken: r.FormValue("csrf_token"), Identifier: r.FormValue("identifier"), Password: r.FormValue("password"), } // Submit the login flow _, _, err := ory.FrontendApi.UpdateLoginFlow(ctx). Flow(flowId). UpdateLoginFlowBody(body). Execute() if err != nil { http.Error(w, "Login failed: "+err.Error(), http.StatusUnauthorized) return } // On success, redirect to wherever you want (e.g., OIDC consent) http.Redirect(w, r, "/success", http.StatusSeeOther) } func main() { http.HandleFunc("/login", handleLogin) http.HandleFunc("/login/submit", handleLoginSubmit) log.Println("Listening on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) }
What this code does: - /login
initializes a login flow and renders a form using the flow data. - /login/submit
submits the form to Kratos and handles the response. You must: - Replace "<https://%s.projects.oryapis.com>"
and ORY_PROJECT_SLUG
with your actual Ory project slug/environment. - Handle the redirect after successful login (e.g., redirect to Hydra's consent endpoint). - Expand the HTML rendering as needed for your UI. References: - [Ory Kratos Go SDK: Create and Submit Login Flow](https://www.ory.sh/docs/kratos/sdk/go#frontend-api) - [Custom UI Integration: Login Flow](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#create-login-flow) If you need to handle the OIDC login_challenge and redirect back to Hydra, ensure you pass the challenge through the flow and redirect as required by your OIDC setup. The code above provides the core login flow logic in Go as per the official Ory documentation.famous-jackal-2829
06/08/2025, 5:15 AMbrief-egg-61061
06/08/2025, 5:16 AMbrief-egg-61061
06/08/2025, 5:16 AM.LoginChallenge()
method on the CreateNativeLoginFlow
request object. The knowledge sources do not show a way to pass the login_challenge
directly when creating a native login flow using the Go SDK. Instead, the typical approach is: - For browser flows, you can pass the login_challenge
as a query parameter to the /self-service/login/browser
endpoint. - For native flows (API clients), the Go SDK's CreateNativeLoginFlow
does not accept a login_challenge
parameter. This means, if you are building a custom login page for OIDC with Hydra and Kratos using the Go SDK, you cannot pass the login_challenge
directly when creating a native login flow. You may need to use the browser flow for OIDC login integrations, as the browser flow supports the login_challenge
parameter in the query string, according to the API reference: > This value is set using the login_challenge
query parameter of the registration and login endpoints. If set will cooperate with Ory OAuth2 and OpenID to act as an OAuth2 server / OpenID Provider. > [Kratos API Reference – createBrowserLoginFlow](https://www.ory.sh/docs/kratos/reference/api) Summary: - The Go SDK for native flows does not support passing login_challenge
. - For OIDC login with Hydra, use the browser flow and pass login_challenge
as a query parameter. If you need to use the Go SDK for a native app, you will not be able to pass the login_challenge
and thus cannot complete the OIDC login flow as required by Hydra. For OIDC, you should use the browser flow and handle the login_challenge
in your HTTP handler by passing it as a query parameter. I'm sorry, but the knowledge sources do not provide a way to pass login_challenge
in the Go SDK's native login flow. If you need to support OIDC with Hydra, you must use the browser flow and not the native flow in this context[Kratos API Reference – createBrowserLoginFlow](https://www.ory.sh/docs/kratos/reference/api).famous-jackal-2829
06/08/2025, 5:17 AMbrief-egg-61061
06/08/2025, 5:17 AMbrief-egg-61061
06/08/2025, 5:18 AMlogin_challenge
as a query parameter to the /self-service/login/browser
endpoint. - The Go SDK does not support passing login_challenge
in the native flow. - You should redirect the user to the browser flow initialization endpoint, including the login_challenge
if present, and then render the login form using the flow data. - On form submission, POST the data to the flow's ui.action
URL. Below is a minimal Go HTTP server that demonstrates this flow: go package main import ( "encoding/json" "html/template" "log" "net/http" "os" "fmt" ) var oryProjectSlug = os.Getenv("ORY_PROJECT_SLUG") // Helper to build the Kratos public URL func kratosPublicURL() string { return fmt.Sprintf("<https://%s.projects.oryapis.com>", oryProjectSlug) } // Handler to initialize the login flow (browser flow) func handleLogin(w http.ResponseWriter, r *http.Request) { loginChallenge := r.URL.Query().Get("login_challenge") flow := r.URL.Query().Get("flow") // If no flow, redirect to Kratos to initialize the flow (with login_challenge if present) if flow == "" { redirectURL := kratosPublicURL() + "/self-service/login/browser" if loginChallenge != "" { redirectURL += "?login_challenge=" + loginChallenge } http.Redirect(w, r, redirectURL, http.StatusFound) return } // Fetch the flow data from Kratos flowURL := kratosPublicURL() + "/self-service/login/flows?id=" + flow req, err := http.NewRequest("GET", flowURL, nil) if err != nil { http.Error(w, "Failed to create request: "+err.Error(), http.StatusInternalServerError) return } // Forward cookies for CSRF/session req.Header.Set("Cookie", r.Header.Get("Cookie")) req.Header.Set("Accept", "application/json") resp, err := <http://http.DefaultClient.Do|http.DefaultClient.Do>(req) if err != nil { http.Error(w, "Failed to fetch flow: "+err.Error(), http.StatusInternalServerError) return } defer resp.Body.Close() var flowData map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&flowData); err != nil { http.Error(w, "Failed to decode flow: "+err.Error(), http.StatusInternalServerError) return } // Render a simple login form using the flow data tmpl := template.Must(template.New("login").Parse(` <form action="{{.ui.action}}" method="{{.ui.method}}"> {{range .ui.nodes}} {{if eq .attributes.name "csrf_token"}} <input type="hidden" name="csrf_token" value="{{.attributes.value}}"> {{end}} {{if eq .attributes.name "identifier"}} <label>ID</label> <input type="text" name="identifier" required> {{end}} {{if eq .attributes.name "password"}} <label>Password</label> <input type="password" name="password" required> {{end}} {{if eq .attributes.name "method"}} <input type="submit" name="method" value="password"> {{end}} {{end}} </form> `)) tmpl.Execute(w, flowData) } func main() { http.HandleFunc("/login", handleLogin) log.Println("Listening on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) }
How this works: - User visits /login?login_challenge=...
- If no flow
parameter, the handler redirects to Kratos' /self-service/login/browser?login_challenge=...
- Kratos redirects back to /login?flow=...&login_challenge=...
- The handler fetches the flow data and renders a login form using the UI nodes from Kratos - The form submits directly to Kratos using the ui.action
and ui.method
from the flow data Notes: - This code is minimal and for demonstration. In production, you should handle errors, edge cases, and security concerns. - The form is rendered using the UI nodes provided by Kratos, as shown in the knowledge sources. - The actual login submission is handled by Kratos, not your Go server. References: - [Create login flow (browser) and pass login_challenge](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#create-login-flow) - [Get login flow and render UI nodes](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#get-login-flow) - [Submit login flow](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#submit-login-flow) If you need to handle the POST response (e.g., to redirect to Hydra's consent endpoint), you can set the return_to
parameter when initializing the flow, as described in the Ory documentation.famous-jackal-2829
06/08/2025, 5:19 AMbrief-egg-61061
06/08/2025, 5:19 AMbrief-egg-61061
06/08/2025, 5:20 AM/oauth2/auth
endpoint by the OAuth2 client. Hydra checks for a user session. If none exists, it redirects the user to your login UI with a login_challenge
query parameter (e.g., /login?login_challenge=...
) [see flow steps](https://www.ory.sh/docs/oauth2-oidc/custom-login-consent/flow#flow-steps). 2. Initialize Login Flow Your login UI receives the request with login_challenge
. It initializes a Kratos browser login flow by redirecting the browser to: /self-service/login/browser?login_challenge=...
Kratos creates a login flow and redirects back to your UI with a flow
parameter (e.g., /login?flow=...&login_challenge=...
) [see initialize login flow](https://www.ory.sh/docs/kratos/self-service/flows/user-login#initialize-login-flow). 3. Render Login Form Your UI fetches the login flow data from Kratos: /self-service/login/flows?id=<flow_id>
Use the returned UI nodes to render the login form (fields for CSRF token, identifier, password, etc.) [see get login flow](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#get-login-flow). 4. Submit Login Form The user submits the form to the Kratos endpoint specified in the flow’s ui.action
(usually /self-service/login?flow=...
). Kratos processes the credentials and, on success, redirects the user back to Hydra to continue the OIDC flow [see submit login flow](https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#submit-login-flow). 5. Hydra Consent Hydra receives the authenticated user and proceeds to the consent step, redirecting the user to your consent UI. --- Summary: - Hydra → your login UI (login_challenge
) - Your UI → Kratos (/self-service/login/browser?login_challenge=...
) - Kratos → your UI (/login?flow=...&login_challenge=...
) - Your UI → Kratos (fetch flow, render form, submit form) - Kratos → Hydra (on success, continue OIDC flow) This is the standard and recommended flow for integrating Ory Kratos and Hydra for OIDC login, as described in the official documentation.