diff --git a/.schema/api.swagger.json b/.schema/api.swagger.json index e7e44c53b90..3cfe676851e 100755 --- a/.schema/api.swagger.json +++ b/.schema/api.swagger.json @@ -535,31 +535,6 @@ } } }, - "/self-service/browser/flows/registration": { - "get": { - "description": "This endpoint initializes a browser-based user registration flow. Once initialized, the browser will be redirected to\n`selfservice.flows.registration.ui_url` with the request ID set as a query parameter. If a valid user session exists already, the browser will be\nredirected to `urls.default_redirect_url`.\n\n\u003e This endpoint is NOT INTENDED for API clients and only works\nwith browsers (Chrome, Firefox, ...).\n\nMore information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration).", - "schemes": [ - "http", - "https" - ], - "tags": [ - "public" - ], - "summary": "Initialize browser-based registration user flow", - "operationId": "initializeSelfServiceBrowserRegistrationFlow", - "responses": { - "302": { - "description": "Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is\ntypically 201." - }, - "500": { - "description": "genericError", - "schema": { - "$ref": "#/definitions/genericError" - } - } - } - } - }, "/self-service/browser/flows/registration/strategies/oidc/settings/connections": { "post": { "description": "This endpoint completes a browser-based settings flow. This is usually achieved by POSTing data to this\nendpoint.\n\n\u003e This endpoint is NOT INTENDED for API clients and only works with browsers (Chrome, Firefox, ...) and HTML Forms.\n\nMore information can be found at [ORY Kratos User Settings \u0026 Profile Management Documentation](../self-service/flows/user-settings).", @@ -649,66 +624,6 @@ } } }, - "/self-service/browser/flows/requests/registration": { - "get": { - "description": "This endpoint returns a registration request's context with, for example, error details and\nother information.\n\nWhen accessing this endpoint through ORY Kratos' Public API, ensure that cookies are set as they are required for CSRF to work. To prevent\ntoken scanning attacks, the public endpoint does not return 404 status codes.\n\nMore information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration).", - "produces": [ - "application/json" - ], - "schemes": [ - "http", - "https" - ], - "tags": [ - "common", - "public", - "admin" - ], - "summary": "Get the request context of browser-based registration user flows", - "operationId": "getSelfServiceBrowserRegistrationRequest", - "parameters": [ - { - "type": "string", - "description": "Request is the Registration Request ID\n\nThe value for this parameter comes from `request` URL Query parameter sent to your\napplication (e.g. `/registration?request=abcde`).", - "name": "request", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "registrationRequest", - "schema": { - "$ref": "#/definitions/registrationRequest" - } - }, - "403": { - "description": "genericError", - "schema": { - "$ref": "#/definitions/genericError" - } - }, - "404": { - "description": "genericError", - "schema": { - "$ref": "#/definitions/genericError" - } - }, - "410": { - "description": "genericError", - "schema": { - "$ref": "#/definitions/genericError" - } - }, - "500": { - "description": "genericError", - "schema": { - "$ref": "#/definitions/genericError" - } - } - } - } - }, "/self-service/browser/flows/requests/settings": { "get": { "description": "When accessing this endpoint through ORY Kratos' Public API, ensure that cookies are set as they are required\nfor checking the auth session. To prevent scanning attacks, the public endpoint does not return 404 status codes\nbut instead 403 or 500.\n\nMore information can be found at [ORY Kratos User Settings \u0026 Profile Management Documentation](../self-service/flows/user-settings).", @@ -1231,7 +1146,7 @@ }, "/self-service/login/methods/password": { "get": { - "description": "Use this endpoint to complete a login flow by sending an identity's identifier and password. This endpoint\nbehaves differently for API and browser flows.\n\nAPI flows expect `application/json` to be sent in the body and responds with\nHTTP 200 and a application/json body with the session token on success;\nHTTP 400 on form validation errors.\n\nBrowser flows expect `application/x-www-form-urlencoded` to be sent in the body and responds with\na HTTP 302 redirect to the post/after login URL or the `return_to` value if it was set and if the login succeeded;\na HTTP 302 redirect to the login UI URL with the flow ID containing the validation errors otherwise.\n\nMore information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration).", + "description": "Use this endpoint to complete a login flow by sending an identity's identifier and password. This endpoint\nbehaves differently for API and browser flows.\n\nAPI flows expect `application/json` to be sent in the body and responds with\nHTTP 200 and a application/json body with the session token on success;\nHTTP 302 redirect to a fresh login flow if the original flow expired with the appropriate error messages set;\nHTTP 400 on form validation errors.\n\nBrowser flows expect `application/x-www-form-urlencoded` to be sent in the body and responds with\na HTTP 302 redirect to the post/after login URL or the `return_to` value if it was set and if the login succeeded;\na HTTP 302 redirect to the login UI URL with the flow ID containing the validation errors otherwise.\n\nMore information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration).", "consumes": [ "application/json", "application/x-www-form-urlencoded" @@ -1292,6 +1207,127 @@ } } }, + "/self-service/registration/api": { + "get": { + "description": "This endpoint initiates a registration flow for API clients such as mobile devices, smart TVs, and so on.\n\nIf a valid provided session cookie or session token is provided, a 400 Bad Request error\nwill be returned unless the URL query parameter `?refresh=true` is set.\n\nTo fetch an existing registration flow call `/self-service/registration/flows?flow=\u003cflow_id\u003e`.\n\n:::note\n\nThis endpoint is NOT INTENDED for browser applications (Chrome, Firefox, ...). We recommend using this endpoint\nfor server-side browser applications and single page apps (SPA).\n\n:::\n\nMore information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration).", + "schemes": [ + "http", + "https" + ], + "tags": [ + "common", + "public", + "admin" + ], + "summary": "Initialize Registration Flow for API clients", + "operationId": "initializeSelfServiceRegistrationViaAPIFlow", + "responses": { + "200": { + "description": "registrationFlow", + "schema": { + "$ref": "#/definitions/registrationFlow" + } + }, + "400": { + "description": "genericError", + "schema": { + "$ref": "#/definitions/genericError" + } + }, + "500": { + "description": "genericError", + "schema": { + "$ref": "#/definitions/genericError" + } + } + } + } + }, + "/self-service/registration/browser": { + "get": { + "description": "This endpoint initializes a browser-based user registration flow. Once initialized, the browser will be redirected to\n`selfservice.flows.registration.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session\nexists already, the browser will be redirected to `urls.default_redirect_url` unless the query parameter\n`?refresh=true` was set.\n\n:::note\n\nThis endpoint is NOT INTENDED for API clients and only works with browsers (Chrome, Firefox, ...).\n\n:::\n\nMore information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration).", + "schemes": [ + "http", + "https" + ], + "tags": [ + "public" + ], + "summary": "Initialize Registration Flow for browsers", + "operationId": "initializeSelfServiceRegistrationViaBrowserFlow", + "responses": { + "302": { + "description": "Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is\ntypically 201." + }, + "500": { + "description": "genericError", + "schema": { + "$ref": "#/definitions/genericError" + } + } + } + } + }, + "/self-service/registration/flows": { + "get": { + "description": "This endpoint returns a registration flow's context with, for example, error details and other information.\n\nMore information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration).", + "produces": [ + "application/json" + ], + "schemes": [ + "http", + "https" + ], + "tags": [ + "common", + "public", + "admin" + ], + "summary": "Get information about a registration flow", + "operationId": "getSelfServiceRegistrationFlow", + "parameters": [ + { + "type": "string", + "description": "The Registration Flow ID\n\nThe value for this parameter comes from `flow` URL Query parameter sent to your\napplication (e.g. `/registration?flow=abcde`).", + "name": "flow", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "registrationFlow", + "schema": { + "$ref": "#/definitions/registrationFlow" + } + }, + "403": { + "description": "genericError", + "schema": { + "$ref": "#/definitions/genericError" + } + }, + "404": { + "description": "genericError", + "schema": { + "$ref": "#/definitions/genericError" + } + }, + "410": { + "description": "genericError", + "schema": { + "$ref": "#/definitions/genericError" + } + }, + "500": { + "description": "genericError", + "schema": { + "$ref": "#/definitions/genericError" + } + } + } + } + }, "/sessions": { "delete": { "description": "Use this endpoint to revoke a session using its token. This endpoint is particularly useful for API clients\nsuch as mobile apps to log the user out of the system and invalidate the session.\n\nThis endpoint does not remove any HTTP Cookies - use the Self-Service Logout Flow instead.", @@ -1916,7 +1952,7 @@ } } }, - "registrationRequest": { + "registrationFlow": { "type": "object", "required": [ "id", @@ -1930,7 +1966,7 @@ "$ref": "#/definitions/CredentialsType" }, "expires_at": { - "description": "ExpiresAt is the time (UTC) when the request expires. If the user still wishes to log in,\na new request has to be initiated.", + "description": "ExpiresAt is the time (UTC) when the flow expires. If the user still wishes to log in,\na new flow has to be initiated.", "type": "string", "format": "date-time" }, @@ -1938,7 +1974,7 @@ "$ref": "#/definitions/UUID" }, "issued_at": { - "description": "IssuedAt is the time (UTC) when the request occurred.", + "description": "IssuedAt is the time (UTC) when the flow occurred.", "type": "string", "format": "date-time" }, @@ -1946,7 +1982,7 @@ "$ref": "#/definitions/Messages" }, "methods": { - "description": "Methods contains context for all enabled registration methods. If a registration request has been\nprocessed, but for example the password is incorrect, this will contain error messages.", + "description": "Methods contains context for all enabled registration methods. If a registration flow has been\nprocessed, but for example the password is incorrect, this will contain error messages.", "type": "object", "additionalProperties": { "$ref": "#/definitions/registrationRequestMethod" @@ -1955,6 +1991,9 @@ "request_url": { "description": "RequestURL is the initial URL that was requested from ORY Kratos. It can be used\nto forward information contained in the URL's path or query for example.", "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" } } }, @@ -1992,7 +2031,7 @@ "type": "string" }, "providers": { - "description": "Providers is set for the \"oidc\" request method.", + "description": "Providers is set for the \"oidc\" registration method.", "type": "array", "items": { "$ref": "#/definitions/formField" diff --git a/internal/httpclient/client/common/common_client.go b/internal/httpclient/client/common/common_client.go index 3a2c28bac8f..0079ba3b3d7 100644 --- a/internal/httpclient/client/common/common_client.go +++ b/internal/httpclient/client/common/common_client.go @@ -31,18 +31,20 @@ type ClientService interface { GetSelfServiceBrowserRecoveryRequest(params *GetSelfServiceBrowserRecoveryRequestParams) (*GetSelfServiceBrowserRecoveryRequestOK, error) - GetSelfServiceBrowserRegistrationRequest(params *GetSelfServiceBrowserRegistrationRequestParams) (*GetSelfServiceBrowserRegistrationRequestOK, error) - GetSelfServiceBrowserSettingsRequest(params *GetSelfServiceBrowserSettingsRequestParams) (*GetSelfServiceBrowserSettingsRequestOK, error) GetSelfServiceError(params *GetSelfServiceErrorParams) (*GetSelfServiceErrorOK, error) GetSelfServiceLoginFlow(params *GetSelfServiceLoginFlowParams) (*GetSelfServiceLoginFlowOK, error) + GetSelfServiceRegistrationFlow(params *GetSelfServiceRegistrationFlowParams) (*GetSelfServiceRegistrationFlowOK, error) + GetSelfServiceVerificationRequest(params *GetSelfServiceVerificationRequestParams) (*GetSelfServiceVerificationRequestOK, error) InitializeSelfServiceLoginViaAPIFlow(params *InitializeSelfServiceLoginViaAPIFlowParams) (*InitializeSelfServiceLoginViaAPIFlowOK, error) + InitializeSelfServiceRegistrationViaAPIFlow(params *InitializeSelfServiceRegistrationViaAPIFlowParams) (*InitializeSelfServiceRegistrationViaAPIFlowOK, error) + SetTransport(transport runtime.ClientTransport) } @@ -120,48 +122,6 @@ func (a *Client) GetSelfServiceBrowserRecoveryRequest(params *GetSelfServiceBrow panic(msg) } -/* - GetSelfServiceBrowserRegistrationRequest gets the request context of browser based registration user flows - - This endpoint returns a registration request's context with, for example, error details and -other information. - -When accessing this endpoint through ORY Kratos' Public API, ensure that cookies are set as they are required for CSRF to work. To prevent -token scanning attacks, the public endpoint does not return 404 status codes. - -More information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration). -*/ -func (a *Client) GetSelfServiceBrowserRegistrationRequest(params *GetSelfServiceBrowserRegistrationRequestParams) (*GetSelfServiceBrowserRegistrationRequestOK, error) { - // TODO: Validate the params before sending - if params == nil { - params = NewGetSelfServiceBrowserRegistrationRequestParams() - } - - result, err := a.transport.Submit(&runtime.ClientOperation{ - ID: "getSelfServiceBrowserRegistrationRequest", - Method: "GET", - PathPattern: "/self-service/browser/flows/requests/registration", - ProducesMediaTypes: []string{"application/json"}, - ConsumesMediaTypes: []string{"application/json", "application/x-www-form-urlencoded"}, - Schemes: []string{"http", "https"}, - Params: params, - Reader: &GetSelfServiceBrowserRegistrationRequestReader{formats: a.formats}, - Context: params.Context, - Client: params.HTTPClient, - }) - if err != nil { - return nil, err - } - success, ok := result.(*GetSelfServiceBrowserRegistrationRequestOK) - if ok { - return success, nil - } - // unexpected success response - // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue - msg := fmt.Sprintf("unexpected success response for getSelfServiceBrowserRegistrationRequest: API contract not enforced by server. Client expected to get an error, but got: %T", result) - panic(msg) -} - /* GetSelfServiceBrowserSettingsRequest gets the request context of browser based settings flows @@ -285,6 +245,44 @@ func (a *Client) GetSelfServiceLoginFlow(params *GetSelfServiceLoginFlowParams) panic(msg) } +/* + GetSelfServiceRegistrationFlow gets information about a registration flow + + This endpoint returns a registration flow's context with, for example, error details and other information. + +More information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration). +*/ +func (a *Client) GetSelfServiceRegistrationFlow(params *GetSelfServiceRegistrationFlowParams) (*GetSelfServiceRegistrationFlowOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewGetSelfServiceRegistrationFlowParams() + } + + result, err := a.transport.Submit(&runtime.ClientOperation{ + ID: "getSelfServiceRegistrationFlow", + Method: "GET", + PathPattern: "/self-service/registration/flows", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json", "application/x-www-form-urlencoded"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &GetSelfServiceRegistrationFlowReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + }) + if err != nil { + return nil, err + } + success, ok := result.(*GetSelfServiceRegistrationFlowOK) + if ok { + return success, nil + } + // unexpected success response + // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue + msg := fmt.Sprintf("unexpected success response for getSelfServiceRegistrationFlow: API contract not enforced by server. Client expected to get an error, but got: %T", result) + panic(msg) +} + /* GetSelfServiceVerificationRequest gets the request context of browser based verification flows @@ -375,6 +373,56 @@ func (a *Client) InitializeSelfServiceLoginViaAPIFlow(params *InitializeSelfServ panic(msg) } +/* + InitializeSelfServiceRegistrationViaAPIFlow initializes registration flow for API clients + + This endpoint initiates a registration flow for API clients such as mobile devices, smart TVs, and so on. + +If a valid provided session cookie or session token is provided, a 400 Bad Request error +will be returned unless the URL query parameter `?refresh=true` is set. + +To fetch an existing registration flow call `/self-service/registration/flows?flow=`. + +:::note + +This endpoint is NOT INTENDED for browser applications (Chrome, Firefox, ...). We recommend using this endpoint +for server-side browser applications and single page apps (SPA). + +::: + +More information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration). +*/ +func (a *Client) InitializeSelfServiceRegistrationViaAPIFlow(params *InitializeSelfServiceRegistrationViaAPIFlowParams) (*InitializeSelfServiceRegistrationViaAPIFlowOK, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewInitializeSelfServiceRegistrationViaAPIFlowParams() + } + + result, err := a.transport.Submit(&runtime.ClientOperation{ + ID: "initializeSelfServiceRegistrationViaAPIFlow", + Method: "GET", + PathPattern: "/self-service/registration/api", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json", "application/x-www-form-urlencoded"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &InitializeSelfServiceRegistrationViaAPIFlowReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + }) + if err != nil { + return nil, err + } + success, ok := result.(*InitializeSelfServiceRegistrationViaAPIFlowOK) + if ok { + return success, nil + } + // unexpected success response + // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue + msg := fmt.Sprintf("unexpected success response for initializeSelfServiceRegistrationViaAPIFlow: API contract not enforced by server. Client expected to get an error, but got: %T", result) + panic(msg) +} + // SetTransport changes the transport on the client func (a *Client) SetTransport(transport runtime.ClientTransport) { a.transport = transport diff --git a/internal/httpclient/client/common/get_self_service_browser_registration_request_parameters.go b/internal/httpclient/client/common/get_self_service_browser_registration_request_parameters.go deleted file mode 100644 index 6af50425523..00000000000 --- a/internal/httpclient/client/common/get_self_service_browser_registration_request_parameters.go +++ /dev/null @@ -1,142 +0,0 @@ -// Code generated by go-swagger; DO NOT EDIT. - -package common - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -import ( - "context" - "net/http" - "time" - - "github.com/go-openapi/errors" - "github.com/go-openapi/runtime" - cr "github.com/go-openapi/runtime/client" - "github.com/go-openapi/strfmt" -) - -// NewGetSelfServiceBrowserRegistrationRequestParams creates a new GetSelfServiceBrowserRegistrationRequestParams object -// with the default values initialized. -func NewGetSelfServiceBrowserRegistrationRequestParams() *GetSelfServiceBrowserRegistrationRequestParams { - var () - return &GetSelfServiceBrowserRegistrationRequestParams{ - - timeout: cr.DefaultTimeout, - } -} - -// NewGetSelfServiceBrowserRegistrationRequestParamsWithTimeout creates a new GetSelfServiceBrowserRegistrationRequestParams object -// with the default values initialized, and the ability to set a timeout on a request -func NewGetSelfServiceBrowserRegistrationRequestParamsWithTimeout(timeout time.Duration) *GetSelfServiceBrowserRegistrationRequestParams { - var () - return &GetSelfServiceBrowserRegistrationRequestParams{ - - timeout: timeout, - } -} - -// NewGetSelfServiceBrowserRegistrationRequestParamsWithContext creates a new GetSelfServiceBrowserRegistrationRequestParams object -// with the default values initialized, and the ability to set a context for a request -func NewGetSelfServiceBrowserRegistrationRequestParamsWithContext(ctx context.Context) *GetSelfServiceBrowserRegistrationRequestParams { - var () - return &GetSelfServiceBrowserRegistrationRequestParams{ - - Context: ctx, - } -} - -// NewGetSelfServiceBrowserRegistrationRequestParamsWithHTTPClient creates a new GetSelfServiceBrowserRegistrationRequestParams object -// with the default values initialized, and the ability to set a custom HTTPClient for a request -func NewGetSelfServiceBrowserRegistrationRequestParamsWithHTTPClient(client *http.Client) *GetSelfServiceBrowserRegistrationRequestParams { - var () - return &GetSelfServiceBrowserRegistrationRequestParams{ - HTTPClient: client, - } -} - -/*GetSelfServiceBrowserRegistrationRequestParams contains all the parameters to send to the API endpoint -for the get self service browser registration request operation typically these are written to a http.Request -*/ -type GetSelfServiceBrowserRegistrationRequestParams struct { - - /*Request - Request is the Registration Request ID - - The value for this parameter comes from `request` URL Query parameter sent to your - application (e.g. `/registration?request=abcde`). - - */ - Request string - - timeout time.Duration - Context context.Context - HTTPClient *http.Client -} - -// WithTimeout adds the timeout to the get self service browser registration request params -func (o *GetSelfServiceBrowserRegistrationRequestParams) WithTimeout(timeout time.Duration) *GetSelfServiceBrowserRegistrationRequestParams { - o.SetTimeout(timeout) - return o -} - -// SetTimeout adds the timeout to the get self service browser registration request params -func (o *GetSelfServiceBrowserRegistrationRequestParams) SetTimeout(timeout time.Duration) { - o.timeout = timeout -} - -// WithContext adds the context to the get self service browser registration request params -func (o *GetSelfServiceBrowserRegistrationRequestParams) WithContext(ctx context.Context) *GetSelfServiceBrowserRegistrationRequestParams { - o.SetContext(ctx) - return o -} - -// SetContext adds the context to the get self service browser registration request params -func (o *GetSelfServiceBrowserRegistrationRequestParams) SetContext(ctx context.Context) { - o.Context = ctx -} - -// WithHTTPClient adds the HTTPClient to the get self service browser registration request params -func (o *GetSelfServiceBrowserRegistrationRequestParams) WithHTTPClient(client *http.Client) *GetSelfServiceBrowserRegistrationRequestParams { - o.SetHTTPClient(client) - return o -} - -// SetHTTPClient adds the HTTPClient to the get self service browser registration request params -func (o *GetSelfServiceBrowserRegistrationRequestParams) SetHTTPClient(client *http.Client) { - o.HTTPClient = client -} - -// WithRequest adds the request to the get self service browser registration request params -func (o *GetSelfServiceBrowserRegistrationRequestParams) WithRequest(request string) *GetSelfServiceBrowserRegistrationRequestParams { - o.SetRequest(request) - return o -} - -// SetRequest adds the request to the get self service browser registration request params -func (o *GetSelfServiceBrowserRegistrationRequestParams) SetRequest(request string) { - o.Request = request -} - -// WriteToRequest writes these params to a swagger request -func (o *GetSelfServiceBrowserRegistrationRequestParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { - - if err := r.SetTimeout(o.timeout); err != nil { - return err - } - var res []error - - // query param request - qrRequest := o.Request - qRequest := qrRequest - if qRequest != "" { - if err := r.SetQueryParam("request", qRequest); err != nil { - return err - } - } - - if len(res) > 0 { - return errors.CompositeValidationError(res...) - } - return nil -} diff --git a/internal/httpclient/client/common/get_self_service_browser_registration_request_responses.go b/internal/httpclient/client/common/get_self_service_browser_registration_request_responses.go deleted file mode 100644 index 932cb3f2074..00000000000 --- a/internal/httpclient/client/common/get_self_service_browser_registration_request_responses.go +++ /dev/null @@ -1,225 +0,0 @@ -// Code generated by go-swagger; DO NOT EDIT. - -package common - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -import ( - "fmt" - "io" - - "github.com/go-openapi/runtime" - "github.com/go-openapi/strfmt" - - "github.com/ory/kratos/internal/httpclient/models" -) - -// GetSelfServiceBrowserRegistrationRequestReader is a Reader for the GetSelfServiceBrowserRegistrationRequest structure. -type GetSelfServiceBrowserRegistrationRequestReader struct { - formats strfmt.Registry -} - -// ReadResponse reads a server response into the received o. -func (o *GetSelfServiceBrowserRegistrationRequestReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { - switch response.Code() { - case 200: - result := NewGetSelfServiceBrowserRegistrationRequestOK() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return result, nil - case 403: - result := NewGetSelfServiceBrowserRegistrationRequestForbidden() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return nil, result - case 404: - result := NewGetSelfServiceBrowserRegistrationRequestNotFound() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return nil, result - case 410: - result := NewGetSelfServiceBrowserRegistrationRequestGone() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return nil, result - case 500: - result := NewGetSelfServiceBrowserRegistrationRequestInternalServerError() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return nil, result - - default: - return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) - } -} - -// NewGetSelfServiceBrowserRegistrationRequestOK creates a GetSelfServiceBrowserRegistrationRequestOK with default headers values -func NewGetSelfServiceBrowserRegistrationRequestOK() *GetSelfServiceBrowserRegistrationRequestOK { - return &GetSelfServiceBrowserRegistrationRequestOK{} -} - -/*GetSelfServiceBrowserRegistrationRequestOK handles this case with default header values. - -registrationRequest -*/ -type GetSelfServiceBrowserRegistrationRequestOK struct { - Payload *models.RegistrationRequest -} - -func (o *GetSelfServiceBrowserRegistrationRequestOK) Error() string { - return fmt.Sprintf("[GET /self-service/browser/flows/requests/registration][%d] getSelfServiceBrowserRegistrationRequestOK %+v", 200, o.Payload) -} - -func (o *GetSelfServiceBrowserRegistrationRequestOK) GetPayload() *models.RegistrationRequest { - return o.Payload -} - -func (o *GetSelfServiceBrowserRegistrationRequestOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - o.Payload = new(models.RegistrationRequest) - - // response payload - if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { - return err - } - - return nil -} - -// NewGetSelfServiceBrowserRegistrationRequestForbidden creates a GetSelfServiceBrowserRegistrationRequestForbidden with default headers values -func NewGetSelfServiceBrowserRegistrationRequestForbidden() *GetSelfServiceBrowserRegistrationRequestForbidden { - return &GetSelfServiceBrowserRegistrationRequestForbidden{} -} - -/*GetSelfServiceBrowserRegistrationRequestForbidden handles this case with default header values. - -genericError -*/ -type GetSelfServiceBrowserRegistrationRequestForbidden struct { - Payload *models.GenericError -} - -func (o *GetSelfServiceBrowserRegistrationRequestForbidden) Error() string { - return fmt.Sprintf("[GET /self-service/browser/flows/requests/registration][%d] getSelfServiceBrowserRegistrationRequestForbidden %+v", 403, o.Payload) -} - -func (o *GetSelfServiceBrowserRegistrationRequestForbidden) GetPayload() *models.GenericError { - return o.Payload -} - -func (o *GetSelfServiceBrowserRegistrationRequestForbidden) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - o.Payload = new(models.GenericError) - - // response payload - if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { - return err - } - - return nil -} - -// NewGetSelfServiceBrowserRegistrationRequestNotFound creates a GetSelfServiceBrowserRegistrationRequestNotFound with default headers values -func NewGetSelfServiceBrowserRegistrationRequestNotFound() *GetSelfServiceBrowserRegistrationRequestNotFound { - return &GetSelfServiceBrowserRegistrationRequestNotFound{} -} - -/*GetSelfServiceBrowserRegistrationRequestNotFound handles this case with default header values. - -genericError -*/ -type GetSelfServiceBrowserRegistrationRequestNotFound struct { - Payload *models.GenericError -} - -func (o *GetSelfServiceBrowserRegistrationRequestNotFound) Error() string { - return fmt.Sprintf("[GET /self-service/browser/flows/requests/registration][%d] getSelfServiceBrowserRegistrationRequestNotFound %+v", 404, o.Payload) -} - -func (o *GetSelfServiceBrowserRegistrationRequestNotFound) GetPayload() *models.GenericError { - return o.Payload -} - -func (o *GetSelfServiceBrowserRegistrationRequestNotFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - o.Payload = new(models.GenericError) - - // response payload - if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { - return err - } - - return nil -} - -// NewGetSelfServiceBrowserRegistrationRequestGone creates a GetSelfServiceBrowserRegistrationRequestGone with default headers values -func NewGetSelfServiceBrowserRegistrationRequestGone() *GetSelfServiceBrowserRegistrationRequestGone { - return &GetSelfServiceBrowserRegistrationRequestGone{} -} - -/*GetSelfServiceBrowserRegistrationRequestGone handles this case with default header values. - -genericError -*/ -type GetSelfServiceBrowserRegistrationRequestGone struct { - Payload *models.GenericError -} - -func (o *GetSelfServiceBrowserRegistrationRequestGone) Error() string { - return fmt.Sprintf("[GET /self-service/browser/flows/requests/registration][%d] getSelfServiceBrowserRegistrationRequestGone %+v", 410, o.Payload) -} - -func (o *GetSelfServiceBrowserRegistrationRequestGone) GetPayload() *models.GenericError { - return o.Payload -} - -func (o *GetSelfServiceBrowserRegistrationRequestGone) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - o.Payload = new(models.GenericError) - - // response payload - if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { - return err - } - - return nil -} - -// NewGetSelfServiceBrowserRegistrationRequestInternalServerError creates a GetSelfServiceBrowserRegistrationRequestInternalServerError with default headers values -func NewGetSelfServiceBrowserRegistrationRequestInternalServerError() *GetSelfServiceBrowserRegistrationRequestInternalServerError { - return &GetSelfServiceBrowserRegistrationRequestInternalServerError{} -} - -/*GetSelfServiceBrowserRegistrationRequestInternalServerError handles this case with default header values. - -genericError -*/ -type GetSelfServiceBrowserRegistrationRequestInternalServerError struct { - Payload *models.GenericError -} - -func (o *GetSelfServiceBrowserRegistrationRequestInternalServerError) Error() string { - return fmt.Sprintf("[GET /self-service/browser/flows/requests/registration][%d] getSelfServiceBrowserRegistrationRequestInternalServerError %+v", 500, o.Payload) -} - -func (o *GetSelfServiceBrowserRegistrationRequestInternalServerError) GetPayload() *models.GenericError { - return o.Payload -} - -func (o *GetSelfServiceBrowserRegistrationRequestInternalServerError) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - o.Payload = new(models.GenericError) - - // response payload - if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { - return err - } - - return nil -} diff --git a/internal/httpclient/client/public/initialize_self_service_browser_registration_flow_parameters.go b/internal/httpclient/client/public/initialize_self_service_browser_registration_flow_parameters.go deleted file mode 100644 index 8e11dc9018d..00000000000 --- a/internal/httpclient/client/public/initialize_self_service_browser_registration_flow_parameters.go +++ /dev/null @@ -1,112 +0,0 @@ -// Code generated by go-swagger; DO NOT EDIT. - -package public - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -import ( - "context" - "net/http" - "time" - - "github.com/go-openapi/errors" - "github.com/go-openapi/runtime" - cr "github.com/go-openapi/runtime/client" - "github.com/go-openapi/strfmt" -) - -// NewInitializeSelfServiceBrowserRegistrationFlowParams creates a new InitializeSelfServiceBrowserRegistrationFlowParams object -// with the default values initialized. -func NewInitializeSelfServiceBrowserRegistrationFlowParams() *InitializeSelfServiceBrowserRegistrationFlowParams { - - return &InitializeSelfServiceBrowserRegistrationFlowParams{ - - timeout: cr.DefaultTimeout, - } -} - -// NewInitializeSelfServiceBrowserRegistrationFlowParamsWithTimeout creates a new InitializeSelfServiceBrowserRegistrationFlowParams object -// with the default values initialized, and the ability to set a timeout on a request -func NewInitializeSelfServiceBrowserRegistrationFlowParamsWithTimeout(timeout time.Duration) *InitializeSelfServiceBrowserRegistrationFlowParams { - - return &InitializeSelfServiceBrowserRegistrationFlowParams{ - - timeout: timeout, - } -} - -// NewInitializeSelfServiceBrowserRegistrationFlowParamsWithContext creates a new InitializeSelfServiceBrowserRegistrationFlowParams object -// with the default values initialized, and the ability to set a context for a request -func NewInitializeSelfServiceBrowserRegistrationFlowParamsWithContext(ctx context.Context) *InitializeSelfServiceBrowserRegistrationFlowParams { - - return &InitializeSelfServiceBrowserRegistrationFlowParams{ - - Context: ctx, - } -} - -// NewInitializeSelfServiceBrowserRegistrationFlowParamsWithHTTPClient creates a new InitializeSelfServiceBrowserRegistrationFlowParams object -// with the default values initialized, and the ability to set a custom HTTPClient for a request -func NewInitializeSelfServiceBrowserRegistrationFlowParamsWithHTTPClient(client *http.Client) *InitializeSelfServiceBrowserRegistrationFlowParams { - - return &InitializeSelfServiceBrowserRegistrationFlowParams{ - HTTPClient: client, - } -} - -/*InitializeSelfServiceBrowserRegistrationFlowParams contains all the parameters to send to the API endpoint -for the initialize self service browser registration flow operation typically these are written to a http.Request -*/ -type InitializeSelfServiceBrowserRegistrationFlowParams struct { - timeout time.Duration - Context context.Context - HTTPClient *http.Client -} - -// WithTimeout adds the timeout to the initialize self service browser registration flow params -func (o *InitializeSelfServiceBrowserRegistrationFlowParams) WithTimeout(timeout time.Duration) *InitializeSelfServiceBrowserRegistrationFlowParams { - o.SetTimeout(timeout) - return o -} - -// SetTimeout adds the timeout to the initialize self service browser registration flow params -func (o *InitializeSelfServiceBrowserRegistrationFlowParams) SetTimeout(timeout time.Duration) { - o.timeout = timeout -} - -// WithContext adds the context to the initialize self service browser registration flow params -func (o *InitializeSelfServiceBrowserRegistrationFlowParams) WithContext(ctx context.Context) *InitializeSelfServiceBrowserRegistrationFlowParams { - o.SetContext(ctx) - return o -} - -// SetContext adds the context to the initialize self service browser registration flow params -func (o *InitializeSelfServiceBrowserRegistrationFlowParams) SetContext(ctx context.Context) { - o.Context = ctx -} - -// WithHTTPClient adds the HTTPClient to the initialize self service browser registration flow params -func (o *InitializeSelfServiceBrowserRegistrationFlowParams) WithHTTPClient(client *http.Client) *InitializeSelfServiceBrowserRegistrationFlowParams { - o.SetHTTPClient(client) - return o -} - -// SetHTTPClient adds the HTTPClient to the initialize self service browser registration flow params -func (o *InitializeSelfServiceBrowserRegistrationFlowParams) SetHTTPClient(client *http.Client) { - o.HTTPClient = client -} - -// WriteToRequest writes these params to a swagger request -func (o *InitializeSelfServiceBrowserRegistrationFlowParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { - - if err := r.SetTimeout(o.timeout); err != nil { - return err - } - var res []error - - if len(res) > 0 { - return errors.CompositeValidationError(res...) - } - return nil -} diff --git a/internal/httpclient/client/public/initialize_self_service_browser_registration_flow_responses.go b/internal/httpclient/client/public/initialize_self_service_browser_registration_flow_responses.go deleted file mode 100644 index 5b65b686476..00000000000 --- a/internal/httpclient/client/public/initialize_self_service_browser_registration_flow_responses.go +++ /dev/null @@ -1,97 +0,0 @@ -// Code generated by go-swagger; DO NOT EDIT. - -package public - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -import ( - "fmt" - "io" - - "github.com/go-openapi/runtime" - "github.com/go-openapi/strfmt" - - "github.com/ory/kratos/internal/httpclient/models" -) - -// InitializeSelfServiceBrowserRegistrationFlowReader is a Reader for the InitializeSelfServiceBrowserRegistrationFlow structure. -type InitializeSelfServiceBrowserRegistrationFlowReader struct { - formats strfmt.Registry -} - -// ReadResponse reads a server response into the received o. -func (o *InitializeSelfServiceBrowserRegistrationFlowReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { - switch response.Code() { - case 302: - result := NewInitializeSelfServiceBrowserRegistrationFlowFound() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return nil, result - case 500: - result := NewInitializeSelfServiceBrowserRegistrationFlowInternalServerError() - if err := result.readResponse(response, consumer, o.formats); err != nil { - return nil, err - } - return nil, result - - default: - return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) - } -} - -// NewInitializeSelfServiceBrowserRegistrationFlowFound creates a InitializeSelfServiceBrowserRegistrationFlowFound with default headers values -func NewInitializeSelfServiceBrowserRegistrationFlowFound() *InitializeSelfServiceBrowserRegistrationFlowFound { - return &InitializeSelfServiceBrowserRegistrationFlowFound{} -} - -/*InitializeSelfServiceBrowserRegistrationFlowFound handles this case with default header values. - -Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is -typically 201. -*/ -type InitializeSelfServiceBrowserRegistrationFlowFound struct { -} - -func (o *InitializeSelfServiceBrowserRegistrationFlowFound) Error() string { - return fmt.Sprintf("[GET /self-service/browser/flows/registration][%d] initializeSelfServiceBrowserRegistrationFlowFound ", 302) -} - -func (o *InitializeSelfServiceBrowserRegistrationFlowFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - return nil -} - -// NewInitializeSelfServiceBrowserRegistrationFlowInternalServerError creates a InitializeSelfServiceBrowserRegistrationFlowInternalServerError with default headers values -func NewInitializeSelfServiceBrowserRegistrationFlowInternalServerError() *InitializeSelfServiceBrowserRegistrationFlowInternalServerError { - return &InitializeSelfServiceBrowserRegistrationFlowInternalServerError{} -} - -/*InitializeSelfServiceBrowserRegistrationFlowInternalServerError handles this case with default header values. - -genericError -*/ -type InitializeSelfServiceBrowserRegistrationFlowInternalServerError struct { - Payload *models.GenericError -} - -func (o *InitializeSelfServiceBrowserRegistrationFlowInternalServerError) Error() string { - return fmt.Sprintf("[GET /self-service/browser/flows/registration][%d] initializeSelfServiceBrowserRegistrationFlowInternalServerError %+v", 500, o.Payload) -} - -func (o *InitializeSelfServiceBrowserRegistrationFlowInternalServerError) GetPayload() *models.GenericError { - return o.Payload -} - -func (o *InitializeSelfServiceBrowserRegistrationFlowInternalServerError) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { - - o.Payload = new(models.GenericError) - - // response payload - if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { - return err - } - - return nil -} diff --git a/internal/httpclient/client/public/public_client.go b/internal/httpclient/client/public/public_client.go index e668456b226..313929e4010 100644 --- a/internal/httpclient/client/public/public_client.go +++ b/internal/httpclient/client/public/public_client.go @@ -41,14 +41,14 @@ type ClientService interface { InitializeSelfServiceBrowserLogoutFlow(params *InitializeSelfServiceBrowserLogoutFlowParams) error - InitializeSelfServiceBrowserRegistrationFlow(params *InitializeSelfServiceBrowserRegistrationFlowParams) error - InitializeSelfServiceBrowserVerificationFlow(params *InitializeSelfServiceBrowserVerificationFlowParams) error InitializeSelfServiceLoginViaBrowserFlow(params *InitializeSelfServiceLoginViaBrowserFlowParams) error InitializeSelfServiceRecoveryFlow(params *InitializeSelfServiceRecoveryFlowParams) error + InitializeSelfServiceRegistrationViaBrowserFlow(params *InitializeSelfServiceRegistrationViaBrowserFlowParams) error + InitializeSelfServiceSettingsFlow(params *InitializeSelfServiceSettingsFlowParams) error RevokeSession(params *RevokeSessionParams) (*RevokeSessionNoContent, error) @@ -241,6 +241,7 @@ behaves differently for API and browser flows. API flows expect `application/json` to be sent in the body and responds with HTTP 200 and a application/json body with the session token on success; +HTTP 302 redirect to a fresh login flow if the original flow expired with the appropriate error messages set; HTTP 400 on form validation errors. Browser flows expect `application/x-www-form-urlencoded` to be sent in the body and responds with @@ -316,42 +317,6 @@ func (a *Client) InitializeSelfServiceBrowserLogoutFlow(params *InitializeSelfSe return nil } -/* - InitializeSelfServiceBrowserRegistrationFlow initializes browser based registration user flow - - This endpoint initializes a browser-based user registration flow. Once initialized, the browser will be redirected to -`selfservice.flows.registration.ui_url` with the request ID set as a query parameter. If a valid user session exists already, the browser will be -redirected to `urls.default_redirect_url`. - -> This endpoint is NOT INTENDED for API clients and only works -with browsers (Chrome, Firefox, ...). - -More information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration). -*/ -func (a *Client) InitializeSelfServiceBrowserRegistrationFlow(params *InitializeSelfServiceBrowserRegistrationFlowParams) error { - // TODO: Validate the params before sending - if params == nil { - params = NewInitializeSelfServiceBrowserRegistrationFlowParams() - } - - _, err := a.transport.Submit(&runtime.ClientOperation{ - ID: "initializeSelfServiceBrowserRegistrationFlow", - Method: "GET", - PathPattern: "/self-service/browser/flows/registration", - ProducesMediaTypes: []string{"application/json"}, - ConsumesMediaTypes: []string{"application/json", "application/x-www-form-urlencoded"}, - Schemes: []string{"http", "https"}, - Params: params, - Reader: &InitializeSelfServiceBrowserRegistrationFlowReader{formats: a.formats}, - Context: params.Context, - Client: params.HTTPClient, - }) - if err != nil { - return err - } - return nil -} - /* InitializeSelfServiceBrowserVerificationFlow initializes browser based verification flow @@ -464,6 +429,46 @@ func (a *Client) InitializeSelfServiceRecoveryFlow(params *InitializeSelfService return nil } +/* + InitializeSelfServiceRegistrationViaBrowserFlow initializes registration flow for browsers + + This endpoint initializes a browser-based user registration flow. Once initialized, the browser will be redirected to +`selfservice.flows.registration.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session +exists already, the browser will be redirected to `urls.default_redirect_url` unless the query parameter +`?refresh=true` was set. + +:::note + +This endpoint is NOT INTENDED for API clients and only works with browsers (Chrome, Firefox, ...). + +::: + +More information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration). +*/ +func (a *Client) InitializeSelfServiceRegistrationViaBrowserFlow(params *InitializeSelfServiceRegistrationViaBrowserFlowParams) error { + // TODO: Validate the params before sending + if params == nil { + params = NewInitializeSelfServiceRegistrationViaBrowserFlowParams() + } + + _, err := a.transport.Submit(&runtime.ClientOperation{ + ID: "initializeSelfServiceRegistrationViaBrowserFlow", + Method: "GET", + PathPattern: "/self-service/registration/browser", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json", "application/x-www-form-urlencoded"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &InitializeSelfServiceRegistrationViaBrowserFlowReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + }) + if err != nil { + return err + } + return nil +} + /* InitializeSelfServiceSettingsFlow initializes browser based settings flow diff --git a/internal/httpclient/models/registration_request.go b/internal/httpclient/models/registration_request.go deleted file mode 100644 index 11c10eeadd3..00000000000 --- a/internal/httpclient/models/registration_request.go +++ /dev/null @@ -1,204 +0,0 @@ -// Code generated by go-swagger; DO NOT EDIT. - -package models - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -import ( - "github.com/go-openapi/errors" - "github.com/go-openapi/strfmt" - "github.com/go-openapi/swag" - "github.com/go-openapi/validate" -) - -// RegistrationRequest registration request -// -// swagger:model registrationRequest -type RegistrationRequest struct { - - // active - Active CredentialsType `json:"active,omitempty"` - - // ExpiresAt is the time (UTC) when the request expires. If the user still wishes to log in, - // a new request has to be initiated. - // Required: true - // Format: date-time - ExpiresAt *strfmt.DateTime `json:"expires_at"` - - // id - // Required: true - // Format: uuid4 - ID UUID `json:"id"` - - // IssuedAt is the time (UTC) when the request occurred. - // Required: true - // Format: date-time - IssuedAt *strfmt.DateTime `json:"issued_at"` - - // messages - Messages Messages `json:"messages,omitempty"` - - // Methods contains context for all enabled registration methods. If a registration request has been - // processed, but for example the password is incorrect, this will contain error messages. - // Required: true - Methods map[string]RegistrationRequestMethod `json:"methods"` - - // RequestURL is the initial URL that was requested from ORY Kratos. It can be used - // to forward information contained in the URL's path or query for example. - // Required: true - RequestURL *string `json:"request_url"` -} - -// Validate validates this registration request -func (m *RegistrationRequest) Validate(formats strfmt.Registry) error { - var res []error - - if err := m.validateActive(formats); err != nil { - res = append(res, err) - } - - if err := m.validateExpiresAt(formats); err != nil { - res = append(res, err) - } - - if err := m.validateID(formats); err != nil { - res = append(res, err) - } - - if err := m.validateIssuedAt(formats); err != nil { - res = append(res, err) - } - - if err := m.validateMessages(formats); err != nil { - res = append(res, err) - } - - if err := m.validateMethods(formats); err != nil { - res = append(res, err) - } - - if err := m.validateRequestURL(formats); err != nil { - res = append(res, err) - } - - if len(res) > 0 { - return errors.CompositeValidationError(res...) - } - return nil -} - -func (m *RegistrationRequest) validateActive(formats strfmt.Registry) error { - - if swag.IsZero(m.Active) { // not required - return nil - } - - if err := m.Active.Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("active") - } - return err - } - - return nil -} - -func (m *RegistrationRequest) validateExpiresAt(formats strfmt.Registry) error { - - if err := validate.Required("expires_at", "body", m.ExpiresAt); err != nil { - return err - } - - if err := validate.FormatOf("expires_at", "body", "date-time", m.ExpiresAt.String(), formats); err != nil { - return err - } - - return nil -} - -func (m *RegistrationRequest) validateID(formats strfmt.Registry) error { - - if err := m.ID.Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("id") - } - return err - } - - return nil -} - -func (m *RegistrationRequest) validateIssuedAt(formats strfmt.Registry) error { - - if err := validate.Required("issued_at", "body", m.IssuedAt); err != nil { - return err - } - - if err := validate.FormatOf("issued_at", "body", "date-time", m.IssuedAt.String(), formats); err != nil { - return err - } - - return nil -} - -func (m *RegistrationRequest) validateMessages(formats strfmt.Registry) error { - - if swag.IsZero(m.Messages) { // not required - return nil - } - - if err := m.Messages.Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName("messages") - } - return err - } - - return nil -} - -func (m *RegistrationRequest) validateMethods(formats strfmt.Registry) error { - - for k := range m.Methods { - - if err := validate.Required("methods"+"."+k, "body", m.Methods[k]); err != nil { - return err - } - if val, ok := m.Methods[k]; ok { - if err := val.Validate(formats); err != nil { - return err - } - } - - } - - return nil -} - -func (m *RegistrationRequest) validateRequestURL(formats strfmt.Registry) error { - - if err := validate.Required("request_url", "body", m.RequestURL); err != nil { - return err - } - - return nil -} - -// MarshalBinary interface implementation -func (m *RegistrationRequest) MarshalBinary() ([]byte, error) { - if m == nil { - return nil, nil - } - return swag.WriteJSON(m) -} - -// UnmarshalBinary interface implementation -func (m *RegistrationRequest) UnmarshalBinary(b []byte) error { - var res RegistrationRequest - if err := swag.ReadJSON(b, &res); err != nil { - return err - } - *m = res - return nil -} diff --git a/internal/httpclient/models/registration_request_method_config.go b/internal/httpclient/models/registration_request_method_config.go index 6c0ecc99d58..9c9a82044fb 100644 --- a/internal/httpclient/models/registration_request_method_config.go +++ b/internal/httpclient/models/registration_request_method_config.go @@ -34,7 +34,7 @@ type RegistrationRequestMethodConfig struct { // Required: true Method *string `json:"method"` - // Providers is set for the "oidc" request method. + // Providers is set for the "oidc" registration method. Providers []*FormField `json:"providers"` } diff --git a/internal/testhelpers/selfservice.go b/internal/testhelpers/selfservice.go index 6bdb61d0b57..0e3d7b36eec 100644 --- a/internal/testhelpers/selfservice.go +++ b/internal/testhelpers/selfservice.go @@ -132,7 +132,7 @@ func SelfServiceHookLoginErrorHandler(t *testing.T, w http.ResponseWriter, r *ht } func SelfServiceHookRegistrationErrorHandler(t *testing.T, w http.ResponseWriter, r *http.Request, err error) bool { - return selfServiceHookErrorHandler(t, w, r, registration.ErrHookAbortRequest, err) + return selfServiceHookErrorHandler(t, w, r, registration.ErrHookAbortFlow, err) } func SelfServiceHookSettingsErrorHandler(t *testing.T, w http.ResponseWriter, r *http.Request, err error) bool { diff --git a/selfservice/flow/registration/error.go b/selfservice/flow/registration/error.go index 60dc55fb2ef..9e9efa50338 100644 --- a/selfservice/flow/registration/error.go +++ b/selfservice/flow/registration/error.go @@ -21,7 +21,8 @@ import ( ) var ( - ErrHookAbortRequest = errors.New("aborted registration hook execution") + ErrHookAbortFlow = errors.New("aborted registration hook execution") + ErrAlreadyLoggedIn = herodot.ErrBadRequest.WithReason("A valid session was detected and thus registration is not possible.") ) type ( @@ -79,7 +80,7 @@ func (s *ErrorHandler) WriteFlowError( if e := new(FlowExpiredError); errors.As(err, &e) { // create new flow because the old one is not valid - a, err := s.d.RegistrationHandler().NewRegistrationFlow(w, r) + a, err := s.d.RegistrationHandler().NewRegistrationFlow(w, r, rr.Type) if err != nil { // failed to create a new session and redirect to it, handle that error as a new one s.WriteFlowError(w, r, ct, rr, err) @@ -147,4 +148,3 @@ func (s *ErrorHandler) forward(w http.ResponseWriter, r *http.Request, rr *Flow, s.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) } } - diff --git a/selfservice/flow/registration/flow.go b/selfservice/flow/registration/flow.go index 78185fa5cc8..a0e4aeedc43 100644 --- a/selfservice/flow/registration/flow.go +++ b/selfservice/flow/registration/flow.go @@ -16,7 +16,7 @@ import ( "github.com/ory/kratos/x" ) -// swagger:model registrationRequest +// swagger:model registrationFlow type Flow struct { // ID represents the flow's unique ID. When performing the registration flow, this // represents the id in the registration ui's query parameter: http:///?flow= @@ -70,7 +70,7 @@ type Flow struct { UpdatedAt time.Time `json:"-" faker:"-" db:"updated_at"` // CSRFToken contains the anti-csrf token associated with this flow. Only set for browser flows. - CSRFToken string `json:"-" db:"csrf_token,omitempty"` + CSRFToken string `json:"-" db:"csrf_token"` } func NewFlow(exp time.Duration, csrf string, r *http.Request, ft flow.Type) *Flow { diff --git a/selfservice/flow/registration/handler.go b/selfservice/flow/registration/handler.go index 0d333f1749c..9e89a2330e9 100644 --- a/selfservice/flow/registration/handler.go +++ b/selfservice/flow/registration/handler.go @@ -6,7 +6,6 @@ import ( "time" "github.com/julienschmidt/httprouter" - "github.com/justinas/nosurf" "github.com/pkg/errors" "github.com/ory/x/urlx" @@ -19,8 +18,10 @@ import ( ) const ( - RouteInitBrowserFlow = "/self-service/browser/flows/registration" - RouteGetFlow = "/self-service/browser/flows/requests/registration" + RouteInitBrowserFlow = "/self-service/registration/browser" + RouteInitAPIFlow = "/self-service/registration/api" + + RouteGetFlow = "/self-service/registration/flows" ) type ( @@ -49,15 +50,18 @@ func NewHandler(d handlerDependencies, c configuration.Provider) *Handler { func (h *Handler) RegisterPublicRoutes(public *x.RouterPublic) { public.GET(RouteInitBrowserFlow, h.d.SessionHandler().IsNotAuthenticated(h.initBrowserFlow, session.RedirectOnAuthenticated(h.c))) - public.GET(RouteGetFlow, h.publicFetchRegistrationFlow) + public.GET(RouteInitAPIFlow, h.d.SessionHandler().IsNotAuthenticated(h.initApiFlow, + session.RespondWithJSONErrorOnAuthenticated(h.d.Writer(), errors.WithStack(ErrAlreadyLoggedIn)))) + + public.GET(RouteGetFlow, h.fetchFlow) } func (h *Handler) RegisterAdminRoutes(admin *x.RouterAdmin) { - admin.GET(RouteGetFlow, h.adminFetchRegistrationFlow) + admin.GET(RouteGetFlow, h.fetchFlow) } -func (h *Handler) NewRegistrationFlow(w http.ResponseWriter, r *http.Request) (*Flow, error) { - a := NewFlow(h.c.SelfServiceFlowRegistrationRequestLifespan(), h.d.GenerateCSRFToken(r), r, flow.TypeBrowser) +func (h *Handler) NewRegistrationFlow(w http.ResponseWriter, r *http.Request, ft flow.Type) (*Flow, error) { + a := NewFlow(h.c.SelfServiceFlowRegistrationRequestLifespan(), h.d.GenerateCSRFToken(r), r, ft) for _, s := range h.d.RegistrationStrategies() { if err := s.PopulateRegistrationMethod(r, a); err != nil { return nil, err @@ -75,26 +79,72 @@ func (h *Handler) NewRegistrationFlow(w http.ResponseWriter, r *http.Request) (* return a, nil } -// swagger:route GET /self-service/browser/flows/registration public initializeSelfServiceBrowserRegistrationFlow +// swagger:route GET /self-service/registration/api common public admin initializeSelfServiceRegistrationViaAPIFlow +// +// Initialize Registration Flow for API clients +// +// This endpoint initiates a registration flow for API clients such as mobile devices, smart TVs, and so on. +// +// If a valid provided session cookie or session token is provided, a 400 Bad Request error +// will be returned unless the URL query parameter `?refresh=true` is set. +// +// To fetch an existing registration flow call `/self-service/registration/flows?flow=`. +// +// :::note +// +// This endpoint is NOT INTENDED for browser applications (Chrome, Firefox, ...). We recommend using this endpoint +// for server-side browser applications and single page apps (SPA). +// +// ::: +// +// More information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration). // -// Initialize browser-based registration user flow +// Schemes: http, https +// +// Security: +// - sessionToken +// +// Responses: +// 200: registrationFlow +// 400: genericError +// 500: genericError +func (h *Handler) initApiFlow(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + a, err := h.NewRegistrationFlow(w, r, flow.TypeAPI) + if err != nil { + h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) + return + } + + h.d.Writer().Write(w, r, a) +} + +// swagger:route GET /self-service/registration/browser public initializeSelfServiceRegistrationViaBrowserFlow +// +// Initialize Registration Flow for browsers // // This endpoint initializes a browser-based user registration flow. Once initialized, the browser will be redirected to -// `selfservice.flows.registration.ui_url` with the flow ID set as a query parameter. If a valid user session exists already, the browser will be -// redirected to `urls.default_redirect_url`. +// `selfservice.flows.registration.ui_url` with the flow ID set as the query parameter `?flow=`. If a valid user session +// exists already, the browser will be redirected to `urls.default_redirect_url` unless the query parameter +// `?refresh=true` was set. +// +// :::note // -// > This endpoint is NOT INTENDED for API clients and only works -// with browsers (Chrome, Firefox, ...). +// This endpoint is NOT INTENDED for API clients and only works with browsers (Chrome, Firefox, ...). +// +// ::: // // More information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration). // // Schemes: http, https // +// Security: +// - sessionToken +// // Responses: // 302: emptyResponse // 500: genericError func (h *Handler) initBrowserFlow(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - a, err := h.NewRegistrationFlow(w, r) + a, err := h.NewRegistrationFlow(w, r, flow.TypeBrowser) if err != nil { h.d.SelfServiceErrorManager().Forward(r.Context(), w, r, err) return @@ -108,27 +158,23 @@ func (h *Handler) initBrowserFlow(w http.ResponseWriter, r *http.Request, ps htt } // nolint:deadcode,unused -// swagger:parameters getSelfServiceBrowserRegistrationRequest -type getSelfServiceBrowserRegistrationRequestParameters struct { - // Request is the Registration Request ID +// swagger:parameters getSelfServiceRegistrationFlow +type getSelfServiceRegistrationFlow struct { + // The Registration Flow ID // - // The value for this parameter comes from `request` URL Query parameter sent to your - // application (e.g. `/registration?request=abcde`). + // The value for this parameter comes from `flow` URL Query parameter sent to your + // application (e.g. `/registration?flow=abcde`). // // required: true // in: query - Request string `json:"request"` + Flow string `json:"flow"` } -// swagger:route GET /self-service/browser/flows/requests/registration common public admin getSelfServiceBrowserRegistrationRequest -// -// Get the request context of browser-based registration user flows +// swagger:route GET /self-service/registration/flows common public admin getSelfServiceRegistrationFlow // -// This endpoint returns a registration request's context with, for example, error details and -// other information. +// Get information about a registration flow // -// When accessing this endpoint through ORY Kratos' Public API, ensure that cookies are set as they are required for CSRF to work. To prevent -// token scanning attacks, the public endpoint does not return 404 status codes. +// This endpoint returns a registration flow's context with, for example, error details and other information. // // More information can be found at [ORY Kratos User Login and User Registration Documentation](https://www.ory.sh/docs/next/kratos/self-service/flows/user-login-user-registration). // @@ -138,45 +184,24 @@ type getSelfServiceBrowserRegistrationRequestParameters struct { // Schemes: http, https // // Responses: -// 200: registrationRequest +// 200: registrationFlow // 403: genericError // 404: genericError // 410: genericError // 500: genericError -func (h *Handler) publicFetchRegistrationFlow(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - if err := h.fetchRegistrationFlow(w, r, true); err != nil { - h.d.Writer().WriteError(w, r, err) - return - } - -} - -func (h *Handler) adminFetchRegistrationFlow(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - if err := h.fetchRegistrationFlow(w, r, false); err != nil { +func (h *Handler) fetchFlow(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + ar, err := h.d.RegistrationFlowPersister().GetRegistrationFlow(r.Context(), x.ParseUUID(r.URL.Query().Get("flow"))) + if err != nil { h.d.Writer().WriteError(w, r, err) return } -} - -func (h *Handler) fetchRegistrationFlow(w http.ResponseWriter, r *http.Request, isPublic bool) error { - ar, err := h.d.RegistrationFlowPersister().GetRegistrationFlow(r.Context(), x.ParseUUID(r.URL.Query().Get("request"))) - if err != nil { - if isPublic { - return errors.WithStack(x.ErrInvalidCSRFToken.WithTrace(err).WithDebugf("%s", err)) - } - return err - } - - if isPublic && !nosurf.VerifyToken(h.d.GenerateCSRFToken(r), ar.CSRFToken) { - return errors.WithStack(x.ErrInvalidCSRFToken) - } if ar.ExpiresAt.Before(time.Now()) { - return errors.WithStack(x.ErrGone. - WithReason("The registration request has expired. Redirect the user to the login endpoint to initialize a new session."). - WithDetail("redirect_to", urlx.AppendPaths(h.c.SelfPublicURL(), RouteInitBrowserFlow).String())) + h.d.Writer().WriteError(w, r, errors.WithStack(x.ErrGone. + WithReason("The registration flow has expired. Redirect the user to the registration flow init endpoint to initialize a new registration flow."). + WithDetail("redirect_to", urlx.AppendPaths(h.c.SelfPublicURL(), RouteInitBrowserFlow).String()))) + return } h.d.Writer().Write(w, r, ar) - return nil } diff --git a/selfservice/flow/registration/hook.go b/selfservice/flow/registration/hook.go index 20ea26c123b..b455750ddfe 100644 --- a/selfservice/flow/registration/hook.go +++ b/selfservice/flow/registration/hook.go @@ -74,7 +74,7 @@ func NewHookExecutor(d executorDependencies, c configuration.Provider) *HookExec func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Request, ct identity.CredentialsType, a *Flow, i *identity.Identity) error { for _, executor := range e.d.PostRegistrationPrePersistHooks(ct) { if err := executor.ExecutePostRegistrationPrePersistHook(w, r, a, i); err != nil { - if errors.Is(err, ErrHookAbortRequest) { + if errors.Is(err, ErrHookAbortFlow) { return nil } return err @@ -100,7 +100,7 @@ func (e *HookExecutor) PostRegistrationHook(w http.ResponseWriter, r *http.Reque s := session.NewActiveSession(i, e.c, time.Now().UTC()) for _, executor := range e.d.PostRegistrationPostPersistHooks(ct) { if err := executor.ExecutePostRegistrationPostPersistHook(w, r, a, s); err != nil { - if errors.Is(err, ErrHookAbortRequest) { + if errors.Is(err, ErrHookAbortFlow) { return nil } return err diff --git a/selfservice/hook/error.go b/selfservice/hook/error.go index dc2f588106d..3091d8bab9b 100644 --- a/selfservice/hook/error.go +++ b/selfservice/hook/error.go @@ -57,13 +57,13 @@ func (e Error) ExecuteLoginPreHook(w http.ResponseWriter, r *http.Request, a *lo } func (e Error) ExecuteRegistrationPreHook(w http.ResponseWriter, r *http.Request, a *registration.Flow) error { - return e.err("ExecuteRegistrationPreHook", registration.ErrHookAbortRequest) + return e.err("ExecuteRegistrationPreHook", registration.ErrHookAbortFlow) } func (e Error) ExecutePostRegistrationPostPersistHook(w http.ResponseWriter, r *http.Request, a *registration.Flow, s *session.Session) error { - return e.err("ExecutePostRegistrationPostPersistHook", registration.ErrHookAbortRequest) + return e.err("ExecutePostRegistrationPostPersistHook", registration.ErrHookAbortFlow) } func (e Error) ExecutePostRegistrationPrePersistHook(w http.ResponseWriter, r *http.Request, a *registration.Flow, i *identity.Identity) error { - return e.err("ExecutePostRegistrationPrePersistHook", registration.ErrHookAbortRequest) + return e.err("ExecutePostRegistrationPrePersistHook", registration.ErrHookAbortFlow) } diff --git a/selfservice/hook/redirector.go b/selfservice/hook/redirector.go index b03b014b899..ffd3b8f96bd 100644 --- a/selfservice/hook/redirector.go +++ b/selfservice/hook/redirector.go @@ -50,14 +50,14 @@ func (e *Redirector) ExecuteRegistrationPreHook(w http.ResponseWriter, r *http.R if err := e.do(w, r); err != nil { return err } - return errors.WithStack(registration.ErrHookAbortRequest) + return errors.WithStack(registration.ErrHookAbortFlow) } func (e *Redirector) ExecutePostRegistrationPrePersistHook(w http.ResponseWriter, r *http.Request, _ *registration.Flow, _ *identity.Identity) error { if err := e.do(w, r); err != nil { return err } - return errors.WithStack(registration.ErrHookAbortRequest) + return errors.WithStack(registration.ErrHookAbortFlow) } func (e *Redirector) ExecuteSettingsPrePersistHook(w http.ResponseWriter, r *http.Request, _ *settings.Request, _ *identity.Identity) error { diff --git a/selfservice/hook/redirector_test.go b/selfservice/hook/redirector_test.go index 25f93acad7a..c6b7fa0151c 100644 --- a/selfservice/hook/redirector_test.go +++ b/selfservice/hook/redirector_test.go @@ -33,13 +33,13 @@ func TestRedirector(t *testing.T) { require.Error(t, l.ExecuteLoginPostHook(w, r, nil, nil), login.ErrHookAbortFlow) }) router.GET("/c", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - require.Error(t, l.ExecutePostRegistrationPrePersistHook(w, r, nil, nil), registration.ErrHookAbortRequest) + require.Error(t, l.ExecutePostRegistrationPrePersistHook(w, r, nil, nil), registration.ErrHookAbortFlow) }) router.GET("/d", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { require.Error(t, l.ExecuteSettingsPostPersistHook(w, r, nil, nil), settings.ErrHookAbortRequest) }) router.GET("/e", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - require.Error(t, l.ExecutePostRegistrationPrePersistHook(w, r, nil, nil), registration.ErrHookAbortRequest) + require.Error(t, l.ExecutePostRegistrationPrePersistHook(w, r, nil, nil), registration.ErrHookAbortFlow) }) router.GET("/f", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { require.Error(t, l.ExecuteLoginPreHook(w, r, nil), login.ErrHookAbortFlow) diff --git a/selfservice/strategy/oidc/strategy_login.go b/selfservice/strategy/oidc/strategy_login.go index b948533da87..e9259d4c20a 100644 --- a/selfservice/strategy/oidc/strategy_login.go +++ b/selfservice/strategy/oidc/strategy_login.go @@ -10,6 +10,7 @@ import ( "github.com/ory/herodot" "github.com/ory/kratos/identity" + "github.com/ory/kratos/selfservice/flow" "github.com/ory/kratos/selfservice/flow/login" "github.com/ory/kratos/x" ) @@ -46,7 +47,9 @@ func (s *Strategy) processLogin(w http.ResponseWriter, r *http.Request, a *login // This is kinda hacky but the only way to ensure seamless login/registration flows when using OIDC. s.d.Logger().WithField("provider", provider.Config().ID).WithField("subject", claims.Subject).Debug("Received successful OpenID Connect callback but user is not registered. Re-initializing registration flow now.") - aa, err := s.d.RegistrationHandler().NewRegistrationFlow(w, r) + + // This flow only works for browsers anyways. + aa, err := s.d.RegistrationHandler().NewRegistrationFlow(w, r, flow.TypeBrowser) if err != nil { s.handleError(w, r, a.GetID(), provider.Config().ID, nil, err) return diff --git a/selfservice/strategy/oidc/strategy_test.go b/selfservice/strategy/oidc/strategy_test.go index 44721a955ac..688856ca737 100644 --- a/selfservice/strategy/oidc/strategy_test.go +++ b/selfservice/strategy/oidc/strategy_test.go @@ -190,7 +190,7 @@ func TestStrategy(t *testing.T) { var nrr = func(t *testing.T, redirectTo string, exp time.Duration) *registration.Flow { // Use NewLoginFlow to instantiate the request but change the things we need to control a copy of it. req, err := reg.RegistrationHandler().NewRegistrationFlow(httptest.NewRecorder(), - &http.Request{URL: urlx.ParseOrPanic(redirectTo)}) + &http.Request{URL: urlx.ParseOrPanic(redirectTo)}, flow.TypeBrowser) require.NoError(t, err) req.RequestURL = redirectTo req.ExpiresAt = time.Now().Add(exp) diff --git a/selfservice/strategy/password/registration_test.go b/selfservice/strategy/password/registration_test.go index ececa739a02..2a0da1bc077 100644 --- a/selfservice/strategy/password/registration_test.go +++ b/selfservice/strategy/password/registration_test.go @@ -87,7 +87,7 @@ func TestRegistration(t *testing.T) { var newRegistrationRequest = func(t *testing.T, exp time.Duration) *registration.Flow { rr := ®istration.Flow{ ID: x.NewUUID(), - Type: flow.TypeBrowser, + Type: flow.TypeBrowser, IssuedAt: time.Now().UTC(), ExpiresAt: time.Now().UTC().Add(exp), RequestURL: ts.URL, Methods: map[identity.CredentialsType]*registration.FlowMethod{ identity.CredentialsTypePassword: { diff --git a/session/handler.go b/session/handler.go index 22e3f2506e6..9d1f35a166b 100644 --- a/session/handler.go +++ b/session/handler.go @@ -200,3 +200,9 @@ func RedirectOnUnauthenticated(to string) httprouter.Handle { http.Redirect(w, r, to, http.StatusFound) } } + +func RespondWithJSONErrorOnAuthenticated(h herodot.Writer, err error) httprouter.Handle { + return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + h.WriteError(w, r, err) + } +}