Hi all, I get this error: `Could not find a strate...
# talk-kratos
m
Hi all, I get this error:
Could not find a strategy to sign you up with. Did you fill out the form correctly?
When using the Kratos browser API with Axios, but I don't get that error when passing the exact same data over Postman. Can anybody help me see what I'm missing? I have a hunch it has something to do with Axios not being able to access http-only cookies, but then how do I work around that? How is Postman making it work?
Postman Requests GET to:
/self-service/registration/browser
response:
Copy code
{
  "id": "88882fef-3ab1-41d6-99e7-6b89fa16f49a",
  "oauth2_login_challenge": null,
  "type": "browser",
  "expires_at": "2023-03-15T10:13:26.780138765Z",
  "issued_at": "2023-03-15T09:13:26.780138765Z",
  "request_url": "<https://agitated-bose-683mbbds9i.projects.oryapis.com/self-service/registration/browser>",
  "ui": {
    "action": "<https://agitated-bose-683mbbds9i.projects.oryapis.com/self-service/registration?flow=88882fef-3ab1-41d6-99e7-6b89fa16f49a>",
    "method": "POST",
    "nodes": [
      {
        "type": "input",
        "group": "default",
        "attributes": {
          "name": "csrf_token",
          "type": "hidden",
          "value": "lWqRsb/jm22038qqGFb4whgoYhsimmTWoWCCKtPjAAKHLXLYbsM9ZOHAyP2T6P8d5knhgGG2GWT+4yjSZ5xX3g==",
          "required": true,
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {}
      },
      {
        "type": "input",
        "group": "password",
        "attributes": {
          "name": "traits.email",
          "type": "email",
          "required": true,
          "autocomplete": "email",
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {
          "label": {
            "id": 1070002,
            "text": "E-Mail",
            "type": "info"
          }
        }
      },
      {
        "type": "input",
        "group": "password",
        "attributes": {
          "name": "password",
          "type": "password",
          "required": true,
          "autocomplete": "new-password",
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {
          "label": {
            "id": 1070001,
            "text": "Password",
            "type": "info"
          }
        }
      },
      {
        "type": "input",
        "group": "password",
        "attributes": {
          "name": "method",
          "type": "submit",
          "value": "password",
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {
          "label": {
            "id": 1040001,
            "text": "Sign up",
            "type": "info",
            "context": {}
          }
        }
      }
    ]
  }
}
then, POST to:
/self-service/registration?flow=88882fef-3ab1-41d6-99e7-6b89fa16f49a
with body:
Copy code
{
  "csrf_token": "lWqRsb/jm22038qqGFb4whgoYhsimmTWoWCCKtPjAAKHLXLYbsM9ZOHAyP2T6P8d5knhgGG2GWT+4yjSZ5xX3g==",
  "password": "f@kepassword1!",
  "method": "password",
  "traits": {
    "email": "<mailto:test3@postman.com|test3@postman.com>"
  }
}
response:
Copy code
{
  "session": {
    "id": "776896f6-0911-43b1-81d2-426742255b63",
    "active": true,
    "expires_at": "2023-03-18T09:15:23.435603784Z",
    "authenticated_at": "2023-03-15T09:15:23.491108036Z",
    "authenticator_assurance_level": "aal1",
    "authentication_methods": [
      {
        "method": "password",
        "aal": "aal1",
        "completed_at": "2023-03-15T09:15:23.435750204Z"
      }
    ],
    "issued_at": "2023-03-15T09:15:23.435603784Z",
    "identity": {
      "id": "ca3c54ea-486e-4629-92c2-ab0c49cded3e",
      "schema_id": "<preset://email>",
      "schema_url": "<https://agitated-bose-683mbbds9i.projects.oryapis.com/schemas/cHJlc2V0Oi8vZW1haWw>",
      "state": "active",
      "state_changed_at": "2023-03-15T09:15:23.384434693Z",
      "traits": {
        "email": "<mailto:test3@postman.com|test3@postman.com>"
      },
      "verifiable_addresses": [
        {
          "id": "0e5cd7b7-27ae-4623-9068-04f44b700c2b",
          "value": "<mailto:test3@postman.com|test3@postman.com>",
          "verified": false,
          "via": "email",
          "status": "sent",
          "created_at": "2023-03-15T09:15:23.392703Z",
          "updated_at": "2023-03-15T09:15:23.392703Z"
        }
      ],
      "recovery_addresses": [
        {
          "id": "1710cf19-90ca-4308-aa5a-02da1cc4bbee",
          "value": "<mailto:test3@postman.com|test3@postman.com>",
          "via": "email",
          "created_at": "2023-03-15T09:15:23.402424Z",
          "updated_at": "2023-03-15T09:15:23.402424Z"
        }
      ],
      "metadata_public": null,
      "created_at": "2023-03-15T09:15:23.38698Z",
      "updated_at": "2023-03-15T09:15:23.38698Z"
    },
    "devices": [
      {
        "id": "42cab2f1-5595-4ff7-aad8-f13fbd83c050",
        "ip_address": "18.200.137.213",
        "user_agent": "Go-http-client/1.1",
        "location": "Dublin, IE"
      }
    ]
  },
  "identity": {
    "id": "ca3c54ea-486e-4629-92c2-ab0c49cded3e",
    "schema_id": "<preset://email>",
    "schema_url": "<https://agitated-bose-683mbbds9i.projects.oryapis.com/schemas/cHJlc2V0Oi8vZW1haWw>",
    "state": "active",
    "state_changed_at": "2023-03-15T09:15:23.384434693Z",
    "traits": {
      "email": "<mailto:test3@postman.com|test3@postman.com>"
    },
    "verifiable_addresses": [
      {
        "id": "0e5cd7b7-27ae-4623-9068-04f44b700c2b",
        "value": "<mailto:test3@postman.com|test3@postman.com>",
        "verified": false,
        "via": "email",
        "status": "sent",
        "created_at": "2023-03-15T09:15:23.392703Z",
        "updated_at": "2023-03-15T09:15:23.392703Z"
      }
    ],
    "recovery_addresses": [
      {
        "id": "1710cf19-90ca-4308-aa5a-02da1cc4bbee",
        "value": "<mailto:test3@postman.com|test3@postman.com>",
        "via": "email",
        "created_at": "2023-03-15T09:15:23.402424Z",
        "updated_at": "2023-03-15T09:15:23.402424Z"
      }
    ],
    "metadata_public": null,
    "created_at": "2023-03-15T09:15:23.38698Z",
    "updated_at": "2023-03-15T09:15:23.38698Z"
  }
}
So far so good, but...
In Axios GET to:
/self-service/registration/browser
Response
Copy code
{
  "id": "7a8c2546-f12b-43de-b190-7d573b7f37d5",
  "oauth2_login_challenge": null,
  "type": "browser",
  "expires_at": "2023-03-15T10:56:18.007880493Z",
  "issued_at": "2023-03-15T09:56:18.007880493Z",
  "request_url": "<http://localhost:4000/self-service/registration/browser>",
  "ui": {
    "action": "<http://localhost:4000/self-service/registration?flow=7a8c2546-f12b-43de-b190-7d573b7f37d5>",
    "method": "POST",
    "nodes": [
      {
        "type": "input",
        "group": "default",
        "attributes": {
          "name": "csrf_token",
          "type": "hidden",
          "value": "iW+3r+V+kThXxNNo3lWSd8/ZyMBYcq03Aifr2Zj2QAlOzuExQBzlk3MB8EJvoVwI+u9SBH6I6wl5zOKZcJYZCw==",
          "required": true,
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {}
      },
      {
        "type": "input",
        "group": "password",
        "attributes": {
          "name": "traits.email",
          "type": "email",
          "required": true,
          "autocomplete": "email",
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {
          "label": {
            "id": 1070002,
            "text": "E-Mail",
            "type": "info"
          }
        }
      },
      {
        "type": "input",
        "group": "password",
        "attributes": {
          "name": "password",
          "type": "password",
          "required": true,
          "autocomplete": "new-password",
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {
          "label": {
            "id": 1070001,
            "text": "Password",
            "type": "info"
          }
        }
      },
      {
        "type": "input",
        "group": "password",
        "attributes": {
          "name": "method",
          "type": "submit",
          "value": "password",
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {
          "label": {
            "id": 1040001,
            "text": "Sign up",
            "type": "info",
            "context": {}
          }
        }
      }
    ]
  }
}
then, POST to:
<http://localhost:4000/self-service/registration?flow=7a8c2546-f12b-43de-b190-7d573b7f37d5>
with body:
Copy code
{
  "csrf_token": "iW+3r+V+kThXxNNo3lWSd8/ZyMBYcq03Aifr2Zj2QAlOzuExQBzlk3MB8EJvoVwI+u9SBH6I6wl5zOKZcJYZCw==",
  "password": "f@kepassword1!",
  "method": "password",
  "traits": {
    "email": "<mailto:test3@postman.com|test3@postman.com>"
  }
}
response:
Copy code
{
  "id": "7a8c2546-f12b-43de-b190-7d573b7f37d5",
  "oauth2_login_challenge": null,
  "type": "browser",
  "expires_at": "2023-03-15T10:56:18.00788Z",
  "issued_at": "2023-03-15T09:56:18.00788Z",
  "request_url": "<http://localhost:4000/self-service/registration/browser>",
  "ui": {
    "action": "<http://localhost:4000/self-service/registration?flow=7a8c2546-f12b-43de-b190-7d573b7f37d5>",
    "method": "POST",
    "nodes": [
      {
        "type": "input",
        "group": "default",
        "attributes": {
          "name": "csrf_token",
          "type": "hidden",
          "value": "iW+3r+V+kThXxNNo3lWSd8/ZyMBYcq03Aifr2Zj2QAlOzuExQBzlk3MB8EJvoVwI+u9SBH6I6wl5zOKZcJYZCw==",
          "required": true,
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {}
      },
      {
        "type": "input",
        "group": "password",
        "attributes": {
          "name": "traits.email",
          "type": "email",
          "required": true,
          "autocomplete": "email",
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {
          "label": {
            "id": 1070002,
            "text": "E-Mail",
            "type": "info"
          }
        }
      },
      {
        "type": "input",
        "group": "password",
        "attributes": {
          "name": "password",
          "type": "password",
          "required": true,
          "autocomplete": "new-password",
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {
          "label": {
            "id": 1070001,
            "text": "Password",
            "type": "info"
          }
        }
      },
      {
        "type": "input",
        "group": "password",
        "attributes": {
          "name": "method",
          "type": "submit",
          "value": "password",
          "disabled": false,
          "node_type": "input"
        },
        "messages": [],
        "meta": {
          "label": {
            "id": 1040001,
            "text": "Sign up",
            "type": "info",
            "context": {}
          }
        }
      }
    ],
    "messages": [
      {
        "id": 4010003,
        "text": "Could not find a strategy to sign you up with. Did you fill out the form correctly?",
        "type": "error"
      }
    ]
  }
}
Why?
p
Hi @miniature-sunset-64101 Could you show me where you are initializing the SDK? Also check out this document if you haven't already https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration
m
Hi Alano, I'm trying to avoid the SDK and access the API using Axios. Is this possible? The UI in the SDK does not align with what we need at our company, so I just want the JSON response with the UI node information which we then want to use to create our own React Components without using the UI in the SDK
p
There is no UI in the SDK
m
I got the wrong SDK then, the one I used had pre-baked UI components in Typescript, let me try this thank you
p
I guess you mean Ory Elements? https://github.com/ory/elements
m
Something else still, Ory elements actually looks better, will give it a gander as well thank you
p
🤨 what did you use then? Also Ory Elements are only pre-baked UI components and does not handle state or api calls for you. You still need the SDK (
@ory/client
) to get the data and pass it on to Ory Elements to render it for you.
m
I think I used https://github.com/ory/kratos-selfservice-ui-react-nextjs, which seems to have a few extra opinionated layers to it, maybe that's where I got the wrong idea
But thanks @proud-plumber-24205, I will change my approach to use the client directly and let you know if I run into any problems
One question @proud-plumber-24205, where can I find docs that describe how to use the classes and methods in the Ory Client? The README and the docs I see in Ory describe the concepts, but not the implementation, i.e. how to initialize the client and make a rgeistration in JavaScript
p
m
So, I've managed to make use of the client, doing this:
Copy code
import {Configuration as OryConfiguration} from "@ory/client";
import {FrontendApiFp as OryFrontendApi} from "@ory/client/dist/api";

/* Ory */
const oryConfiguration = new OryConfiguration({
  basePath: process.env.NEXT_PUBLIC_ORY_API_URL
});

const oryAPI = new OryFrontendApi(oryConfiguration);

oryAPI.createBrowserRegistrationFlow().then(async (flow) => {
  const registrationFlowResponse = await flow();
  const csrfToken = registrationFlowResponse.data.ui.nodes.filter((node) => node.attributes.name === "csrf_token").pop().attributes.value;

  <http://console.info|console.info>('Ory Registration Flow Response -->', registrationFlowResponse);
  <http://console.info|console.info>('Ory Registration CSRF Token -->', csrfToken);

  oryAPI.updateRegistrationFlow(registrationFlowResponse.data.id, {
    "csrf_token": csrfToken,
    "password": "Mielie88!",
    "method": "password",
    "traits": {
      "email": "<mailto:testsdk@postman.com|testsdk@postman.com>"
    }
  }).then(async (flow) => {
    const registrationResponse = await flow();

    <http://console.info|console.info>('Ory Registration Response -->', registrationResponse);
  });
}).catch((error) => {
  console.error("Ory Registration Error --->", error);
});
/* END Ory */
However I feel like:
Copy code
const csrfToken = registrationFlowResponse.data.ui.nodes.filter((node) => node.attributes.name === "csrf_token").pop().attributes.value;
is not quite correct, which is why I get the following response:
Copy code
{
  "error": {
    "id": "security_csrf_violation",
    "code": 403,
    "status": "Forbidden",
    "request": "2f16d9c2-5ed9-9133-bcb6-37f88623f6ae",
    "reason": "Please retry the flow and optionally clear your cookies. The request was rejected to protect you from Cross-Site-Request-Forgery (CSRF) which could cause account takeover, leaking personal information, and other serious security issues.",
    "details": {
      "docs": "<https://www.ory.sh/kratos/docs/debug/csrf>",
      "hint": "The anti-CSRF cookie was found but the CSRF token was not included in the HTTP request body (csrf_token) nor in the HTTP Header (X-CSRF-Token).",
      "reject_reason": "The HTTP Cookie Header was set and a CSRF token was sent but they do not match. We recommend deleting all cookies for this domain and retrying the flow."
    },
    "message": "the request was rejected to protect you from Cross-Site-Request-Forgery"
  }
}
@proud-plumber-24205, what is the proper way to ensure that the SDK uses the correct CSRF? Is this supposed to be automatic or is my approach wrong?
p
There are two csrf tokens, 1 stored in the form and another in the browser cookie. You need to tell the SDK to include cookies as shown in the documentation.
Copy code
const frontend = new FrontendApi(
  new Configuration({
    basePath: "<http://localhost:4000>", // Use your local Ory Tunnel URL
    baseOptions: {
      withCredentials: true, // we need to include cookies
    },
  }),
)
https://www.ory.sh/docs/kratos/bring-your-own-ui/custom-ui-basic-integration#create-login-flow
m
Wonderful, works like a charm, thanks @proud-plumber-24205. Sorry to bug, the docs are dense and I only started this yesterday
p
It's no problem, yes this document was a first attempt at explaining Ory properly for Custom UI integration. We will improve it iteratively