Hi, I’m currently working on an application where ...
# general
p
Hi, I’m currently working on an application where I’ve implemented Ory Kratos for user authentication. Kratos is handling user login, verifying their identity, and managing sessions by issuing a session token (cookie). My current flow relies on this session token to restrict access to protected APIs by validating the session and fetching the user information from Kratos. My Current Implementation: 1. The user logs in through Kratos using the self-service login flow. 2. Kratos issues a session token, which I validate before allowing access to my APIs. This ensures that the user is authenticated and their session is active. Questions: • Kratos Implementation: Is relying on the session token issued by Kratos sufficient for managing authentication and securing API access? Are there any improvements or best practices I should follow to make this flow more robust? • How to Use Hydra for Authorization: ◦ I understand that Hydra is used for managing OAuth 2.0 flows and issuing access tokens. How do I integrate Hydra with my existing Kratos setup to handle authorization effectively?
Copy code
import axios from "axios";
import { NextRequest, NextResponse } from "next/server";

export async function POST(req: NextRequest) {
  const reqBody = await req.json();
  const { email, password } = reqBody;
  // console.log("reqBody", reqBody);
  const isDockerized = process.env.DOCKERIZED === "true";
  const apiConfig = isDockerized ? "kratos" : "localhost";

  try {
    const initResponse = await axios.get(
      `http://${apiConfig}:4433/self-service/login/browser`,
      {
        headers: {
          Accept: "application/json",
        },
      }
    );

    // Extract cookies from the response
    const setCookieHeader = initResponse.headers["set-cookie"];
    if (!setCookieHeader) {
      throw new Error("No cookies found in the response");
    }

    // Combine all cookies into a single string
    const cookieString = setCookieHeader.join("; ");

    const flowID = new URL(initResponse.data.ui.action).searchParams.get(
      "flow"
    );

    //how to pass body in this
    const csrfToken = initResponse?.data?.ui?.nodes?.find(
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      (node: any) => node.attributes.name === "csrf_token"
    )?.attributes?.value;

    // Second API call with the cookies attached
    const secondResponse = await <http://axios.post|axios.post>(
      `http://${apiConfig}:4433/self-service/login?flow=${flowID}`,
      new URLSearchParams({
        method: "password",
        password: password,
        csrf_token: csrfToken,
        identifier: email,
      }),
      {
        headers: {
          "Content-Type": "application/x-www-form-urlencoded",
          // "Content-Type":"application/json",
          Accept: "application/json",
          Cookie: cookieString, // Send cookies here
        },
      }
    );

    const secondResponseCookies = secondResponse.headers["set-cookie"];

    if (secondResponse.status == 200 && secondResponseCookies) {
      // res.setHeader('Set-Cookie', `session=${data.session_token}; Path=/; HttpOnly`);
      return NextResponse.json(
        {
          message: "Login successful",
          success: true,
        },
        {
          headers: secondResponseCookies.reduce((headers, cookie) => {
            // Append each cookie as a separate header
            headers.append("Set-Cookie", cookie);
            return headers;
          }, new Headers()),
        }
      );
    } else {
      return NextResponse.json(
        { error: "User does not exist" },
        { status: 400 }
      );
    }
  } catch (error) {
    console.log("error", error);
    return NextResponse.json(
      { error: "Internal Server Error Error", message: error },
      { status: 500 }
    );
  }
}