Hi, I’m implementing a self-service for Kratos but in Java, I can get data from kratos for rendering form. But when I post data to register new identity, I got a error below
{“error”:{“code”:400,“status”:“Bad Request”,“reason”:“CSRF token is missing or invalid.”,“message”:“The request was malformed or contained invalid parameters”}}
When I check the requests in browser, csrf token is similar, but in kratos logs, expected and actual token are different.
Below is registration data from kratos admin api
And request data when do a post to complete registration
Kratos log
oathkeeper_1 | [cors] 2020/03/23 16:11:37 Handler: Actual request oathkeeper_1 | [cors] 2020/03/23 16:11:37 Actual response added headers: map[Access-Control-Allow-Credentials:[true] Access-Control-Allow-Origin:[*] Access-Control-Expose-Headers:[Content-Type] Vary:[Origin]] oathkeeper_1 | {"level":"info","method":"GET","msg":"started handling request","remote":"172.23.0.1:56288","request":"/auth/registration","time":"2020-03-23T16:11:37Z"} oathkeeper_1 | {"granted":true,"http_host":"127.0.0.1:4455","http_method":"GET","http_url":"[http://host.docker.internal:8088/auth/registration](https://slack-redir.net/link?url=http%3A%2F%2Fhost.docker.internal%3A8088%2Fauth%2Fregistration&v=3)","http_user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:74.0) Gecko/20100101 Firefox/74.0","level":"warning","msg":"Access request granted","subject":"guest","time":"2020-03-23T16:11:37Z"} oathkeeper_1 | {"level":"info","measure#oathkeeper-proxy.latency":37000200,"method":"GET","msg":"completed handling request","remote":"172.23.0.1:56288","request":"/auth/registration","status":302,"text_status":"Found","time":"2020-03-23T16:11:37Z","took":37000200} oathkeeper_1 | [cors] 2020/03/23 16:11:37 Handler: Actual request oathkeeper_1 | [cors] 2020/03/23 16:11:37 Actual response added headers: map[Access-Control-Allow-Credentials:[true] Access-Control-Allow-Origin:[*] Access-Control-Expose-Headers:[Content-Type] Vary:[Origin]] oathkeeper_1 | {"level":"info","method":"GET","msg":"started handling request","remote":"172.23.0.1:56288","request":"/.ory/kratos/public/self-service/browser/flows/registration","time":"2020-03-23T16:11:37Z"} kratos_1 | time="2020-03-23T16:11:37Z" level=info msg="started handling request" method=GET name="public#[http://127.0.0.1:4455/.ory/kratos/public/](https://slack-redir.net/link?url=http%3A%2F%2F127.0.0.1%3A4455%2F.ory%2Fkratos%2Fpublic%2F&v=3)" remote="172.23.0.7:39566" request=/self-service/browser/flows/registration kratos_1 | time="2020-03-23T16:11:37Z" level=info msg="completed handling request" method=GET name="public#[http://127.0.0.1:4455/.ory/kratos/public/](https://slack-redir.net/link?url=http%3A%2F%2F127.0.0.1%3A4455%2F.ory%2Fkratos%2Fpublic%2F&v=3)" remote="172.23.0.7:39566" request=/self-service/browser/flows/registration status=302 text_status=Found took=43.5578ms oathkeeper_1 | {"granted":true,"http_host":"127.0.0.1:4455","http_method":"GET","http_url":"[http://kratos:4433/self-service/browser/flows/registration](https://slack-redir.net/link?url=http%3A%2F%2Fkratos%3A4433%2Fself-service%2Fbrowser%2Fflows%2Fregistration&v=3)","http_user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:74.0) Gecko/20100101 Firefox/74.0","level":"warning","msg":"Access request granted","subject":"","time":"2020-03-23T16:11:37Z"} oathkeeper_1 | {"level":"info","measure#oathkeeper-proxy.latency":50985800,"method":"GET","msg":"completed handling request","remote":"172.23.0.1:56288","request":"/.ory/kratos/public/self-service/browser/flows/registration","status":302,"text_status":"Found","time":"2020-03-23T16:11:37Z","took":50985800} oathkeeper_1 | [cors] 2020/03/23 16:11:37 Handler: Actual request oathkeeper_1 | [cors] 2020/03/23 16:11:37 Actual response added headers: map[Access-Control-Allow-Credentials:[true] Access-Control-Allow-Origin:[*] Access-Control-Expose-Headers:[Content-Type] Vary:[Origin]] oathkeeper_1 | {"level":"info","method":"GET","msg":"started handling request","remote":"172.23.0.1:56288","request":"/auth/registration?request=e136e899-7cbb-4068-8181-054005c2812f","time":"2020-03-23T16:11:37Z"} kratos_1 | time="2020-03-23T16:11:37Z" level=info msg="started handling request" method=GET name="admin#[http://kratos:4434/](https://slack-redir.net/link?url=http%3A%2F%2Fkratos%3A4434%2F&v=3)" remote="172.23.0.1:58716" request="//self-service/browser/flows/requests/registration?request=e136e899-7cbb-4068-8181-054005c2812f" kratos_1 | time="2020-03-23T16:11:37Z" level=info msg="completed handling request" method=GET name="admin#[http://kratos:4434/](https://slack-redir.net/link?url=http%3A%2F%2Fkratos%3A4434%2F&v=3)" remote="172.23.0.1:58716" request="//self-service/browser/flows/requests/registration?request=e136e899-7cbb-4068-8181-054005c2812f" status=301 text_status="Moved Permanently" took="700.9µs" oathkeeper_1 | {"granted":true,"http_host":"127.0.0.1:4455","http_method":"GET","http_url":"[http://host.docker.internal:8088/auth/registration?request=e136e899-7cbb-4068-8181-054005c2812f](https://slack-redir.net/link?url=http%3A%2F%2Fhost.docker.internal%3A8088%2Fauth%2Fregistration%3Frequest%3De136e899-7cbb-4068-8181-054005c2812f&v=3)","http_user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:74.0) Gecko/20100101 Firefox/74.0","level":"warning","msg":"Access request granted","subject":"guest","time":"2020-03-23T16:11:37Z"} oathkeeper_1 | {"level":"info","measure#oathkeeper-proxy.latency":87799200,"method":"GET","msg":"completed handling request","remote":"172.23.0.1:56288","request":"/auth/registration?request=e136e899-7cbb-4068-8181-054005c2812f","status":200,"text_status":"OK","time":"2020-03-23T16:11:37Z","took":87799200} kratos_1 | time="2020-03-23T16:11:37Z" level=info msg="started handling request" method=GET name="admin#[http://kratos:4434/](https://slack-redir.net/link?url=http%3A%2F%2Fkratos%3A4434%2F&v=3)" remote="172.23.0.1:58716" request="/self-service/browser/flows/requests/registration?request=e136e899-7cbb-4068-8181-054005c2812f" kratos_1 | time="2020-03-23T16:11:37Z" level=info msg="completed handling request" method=GET name="admin#[http://kratos:4434/](https://slack-redir.net/link?url=http%3A%2F%2Fkratos%3A4434%2F&v=3)" remote="172.23.0.1:58716" request="/self-service/browser/flows/requests/registration?request=e136e899-7cbb-4068-8181-054005c2812f" status=200 text_status=OK took=7.6258ms oathkeeper_1 | {"level":"info","method":"POST","msg":"started handling request","remote":"172.23.0.1:56288","request":"/.ory/kratos/public/self-service/browser/flows/registration/strategies/password?request=e136e899-7cbb-4068-8181-054005c2812f","time":"2020-03-23T16:12:36Z"} oathkeeper_1 | {"granted":true,"http_host":"127.0.0.1:4455","http_method":"POST","http_url":"[http://kratos:4433/self-service/browser/flows/registration/strategies/password?request=e136e899-7cbb-4068-8181-054005c2812f](https://slack-redir.net/link?url=http%3A%2F%2Fkratos%3A4433%2Fself-service%2Fbrowser%2Fflows%2Fregistration%2Fstrategies%2Fpassword%3Frequest%3De136e899-7cbb-4068-8181-054005c2812f&v=3)","http_user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:74.0) Gecko/20100101 Firefox/74.0","level":"warning","msg":"Access request granted","subject":"","time":"2020-03-23T16:12:36Z"} oathkeeper_1 | {"level":"info","measure#oathkeeper-proxy.latency":1736900,"method":"POST","msg":"completed handling request","remote":"172.23.0.1:56288","request":"/.ory/kratos/public/self-service/browser/flows/registration/strategies/password?request=e136e899-7cbb-4068-8181-054005c2812f","status":400,"text_status":"Bad Request","time":"2020-03-23T16:12:36Z","took":1736900} oathkeeper_1 | [cors] 2020/03/23 16:12:36 Handler: Actual request oathkeeper_1 | [cors] 2020/03/23 16:12:36 Actual response added headers: map[Access-Control-Allow-Credentials:[true] Access-Control-Allow-Origin:[*] Access-Control-Expose-Headers:[Content-Type] Vary:[Origin]] kratos_1 | time="2020-03-23T16:12:36Z" level=info msg="started handling request" method=POST name="public#[http://127.0.0.1:4455/.ory/kratos/public/](https://slack-redir.net/link?url=http%3A%2F%2F127.0.0.1%3A4455%2F.ory%2Fkratos%2Fpublic%2F&v=3)" remote="172.23.0.7:39566" request="/self-service/browser/flows/registration/strategies/password?request=e136e899-7cbb-4068-8181-054005c2812f" kratos_1 | time="2020-03-23T16:12:36Z" level=warning msg="A request failed due to a missing or invalid csrf_token value" expected_token="o6NXLbPk68qEfFEE5iCKD4+XANec5n7VZNlNzoF42p8+vpGbQDNpSiBskVQUj5SNqSImUR+zKvp4j+q4FkODWg==" received_token="AFtF6kkDwfeQpoSAi1D2XkAYgybKKgnVnCmpbQdO1SddUJIeFs5wLh1aRYYNiORsIzIob3awjpslBhDwCvLNUQ==" received_token_form="AFtF6kkDwfeQpoSAi1D2XkAYgybKKgnVnCmpbQdO1SddUJIeFs5wLh1aRYYNiORsIzIob3awjpslBhDwCvLNUQ==" kratos_1 | time="2020-03-23T16:12:36Z" level=error msg="An error occurred while handling a request" code=400 debug= details="map[]" error="The request was malformed or contained invalid parameters" reason="CSRF token is missing or invalid." request-id= status=400 writer=JSON kratos_1 | time="2020-03-23T16:12:36Z" level=info msg="completed handling request" method=POST name="public#[http://127.0.0.1:4455/.ory/kratos/public/](https://slack-redir.net/link?url=http%3A%2F%2F127.0.0.1%3A4455%2F.ory%2Fkratos%2Fpublic%2F&v=3)" remote="172.23.0.7:39566" request="/self-service/browser/flows/registration/strategies/password?request=e136e899-7cbb-4068-8181-054005c2812f" status=400 text_status="Bad Request" took="449.9µs"
I don’t use server-rendering, so I create an api in my self-service to return json from kratos, and then my web frontend (react) use this json to populates data.
Here is my java self-service code
import java.net.URI;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import sh.ory.kratos.ApiClient;
import sh.ory.kratos.ApiException;
import sh.ory.kratos.ApiResponse;
import sh.ory.kratos.api.AdminApi;
import sh.ory.kratos.model.RegistrationRequest;
@RestController
@Slf4j
public class RegistrationController {
private final IdpProperties idpProperties;
@Autowired
public RegistrationController(IdpProperties idpProperties) {
this.idpProperties = idpProperties;
}
@GetMapping("auth/registration")
public ResponseEntity<RegistrationRequest> register(
@RequestParam(required = false) String request) {
if (request == null) {
log.info("Parameter 'request' not available");
// redirect
return redirect();
}
log.info(request);
ApiClient client = new ApiClient();
client.setBasePath(idpProperties.getUrl().getKratosAdminApi());
AdminApi adminEndpoint = new AdminApi(client);
try {
ApiResponse<RegistrationRequest> response =
adminEndpoint.getSelfServiceBrowserRegistrationRequestWithHttpInfo(request);
if (response.getStatusCode() == 404
|| response.getStatusCode() == 403
|| response.getStatusCode() == 410) {
// redirect
return redirect();
}
if (response.getStatusCode() == 200) {
RegistrationRequest data = response.getData();
return new ResponseEntity<>(data, HttpStatus.OK);
}
} catch (ApiException e) {
log.error("Kratos connection error", e);
}
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
private ResponseEntity redirect() {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(
URI.create(
idpProperties.getUrl().getKratosBrowser()
+ idpProperties.getUrl().getRegistrationRequest()));
return new ResponseEntity<>(headers, HttpStatus.FOUND);
}
}
Configuration:
idp:
url:
kratos-admin-api: http://127.0.0.1:4434/
kratos-public-api: http://127.0.0.1:4433/
kratos-browser: http://127.0.0.1:4455/.ory/kratos/public
registration-request: /self-service/browser/flows/registration
login-request: /self-service/browser/flows/login
My kratos and oathkeeper config is similar to config files in kratos repository
Any ideas? Thank you!