Hi, I'm new to ory kratos and facing difficulties ...
# general
b
Hi, I'm new to ory kratos and facing difficulties to integrate with next js 14. could you please help me? Please check my code:
Copy code
'use client'

import { useEffect, useState } from "react";
import { SubmitButton } from "@/components/SubmitButton";
import Link from "next/link";
import { Configuration, FrontendApi, LoginFlow } from "@ory/client"
import { useRouter } from "next/navigation";

const basePath = process.env.NEXT_PUBLIC_ORY_SDK_URL;

const ory = new FrontendApi(
    new Configuration({
        basePath: basePath,
        baseOptions: {
            withCredentials: true,
        },
    })
);

export default function LoginForm() {
    const router = useRouter();
    const [userName, setUserName] = useState('');
    const [password, setPassword] = useState('');
    const [flow, setFlow] = useState<LoginFlow>();
    const [error, setError] = useState<string | null>(null);
    const [csrfToken, setCsrfToken] = useState<string | null>(null);
    const [isFlowCreated, setIsFlowCreated] = useState(false); // Track if flow is created    

    useEffect(() => {
        const createLoginFlow = async () => {
            if (flow) {
                console.log("flow already exists!");
                return;
            }

            try {
                const { data } = await ory.createBrowserLoginFlow({
                    refresh: false,
                    aal: undefined,
                    returnTo: undefined,
                });
                setFlow(data);
                console.log(data);
                console.log(data.ui.nodes);

                // Retrieve the CSRF token from the flow response
                const csrfNode = data.ui.nodes.find(node => node.attributes.name === 'csrf_token');
                if (csrfNode) {
                    console.log(csrfNode);
                    setCsrfToken(csrfNode.attributes.value as string);
                }
            } catch (err) {
                console.error("Error creating login flow:", err);
                setError("Could not create login flow. Please try again.");
            }
        };

        if (!isFlowCreated) {
            createLoginFlow();
            setIsFlowCreated(true);
        }

    }, [isFlowCreated, flow]);


    const onSubmitLogin = async (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();

        if (!flow || !csrfToken) {
            setError("Login flow is not available. Please refresh the page.");
            return;
        }

        // router.push(`/login?flow=${flow?.id}`);
        // .then(async () => {
        // await router.push(`/login?flow=${flow?.id}`, undefined, { shallow: true });

        try {
            const response = await ory.updateLoginFlow({
                flow: flow?.id,
                updateLoginFlowBody: {
                    csrf_token: csrfToken,
                    identifier: userName,
                    password: password,
                    method: "password"
                }
            });

            console.log("Login success:", response.data);
            // Redirect or handle login success
        } catch (err: any) {
            console.error("Login failed:", err.response?.data || err);
            setError("Login failed. Please check your credentials.");
        }
        // });


    };


    return (
        <form onSubmit={onSubmitLogin} className="flex flex-col space-y-4 bg-gray-50 px-4 py-8 sm:px-16">
            {error && <div className="text-red-500">{error}</div>}

            <div>
                <label
                    htmlFor="email"
                    className="block text-xs text-gray-600 uppercase"
                >
                    Email Address
                </label>
                <input
                    id="email"
                    name="email"
                    type="email"
                    placeholder="user@example.com"
                    autoComplete="email"
                    value={userName}
                    onChange={(e) => setUserName(e.target.value)}
                    required
                    className="mt-1 block w-full appearance-none rounded-md border border-gray-300 px-3 py-2 placeholder-gray-400 shadow-sm focus:border-black focus:outline-none focus:ring-black sm:text-sm"
                />
            </div>
            <div>
                <label
                    htmlFor="password"
                    className="block text-xs text-gray-600 uppercase"
                >
                    Password
                </label>
                <input
                    id="password"
                    name="password"
                    type="password"
                    value={password}
                    onChange={(e) => setPassword(e.target.value)}
                    required
                    className="mt-1 block w-full appearance-none rounded-md border border-gray-300 px-3 py-2 placeholder-gray-400 shadow-sm focus:border-black focus:outline-none focus:ring-black sm:text-sm"
                />
            </div>


            <SubmitButton>Sign in</SubmitButton>
            <p className="text-center text-sm text-gray-600">
                {"Don't have an account? "}
                <Link href="/register" className="font-semibold text-gray-800">
                    Sign up
                </Link>
                {' for free.'}
            </p>
        </form>
    );
}

// export default LoginForm;
It throws the following exception during login:
Copy code
{
  "error": {
    "id": "security_csrf_violation",
    "code": 403,
    "status": "Forbidden",
    "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"
  }
}
g
Aside from the
csrf_token
return by the payload that is in ui nodes, there's also a
csrf_token
that kratos set to the browser cookie, afaik those need to be both present and match when you process the request
Looks something like this,
Worth checking if both token are present, (if you havent already)
b
Thanks I did a mistake.I set SDK uri to 127.0.0.1 but tried to browse from localhost, that's why it throws the csrf error. now it's working fine