import UriInputField from '@/mdx-components-v2/UriInputField';
import Tabs from '@mdx/components/Tabs';
import TabItem from '@mdx/components/TabItem';
import InlineNotification from '@/ds-components/InlineNotification';
import { buildIdGenerator } from '@logto/shared/universal';
import Steps from '@/mdx-components-v2/Steps';
import Step from '@/mdx-components-v2/Step';

<Steps>

<Step
  title="Add Logto SDK as a dependency"
  subtitle="Please select your favorite package manager"
>
<Tabs>
<TabItem value="npm" label="npm">

```bash
npm i @logto/remix
```

</TabItem>
<TabItem value="yarn" label="Yarn">

```bash
yarn add @logto/remix
```

</TabItem>
<TabItem value="pnpm" label="pnpm">

```bash
pnpm add @logto/remix
```

</TabItem>
</Tabs>
</Step>

<Step
  title="Create SessionStorage"
  subtitle="1 step"
>

Before initializing the SDK, we have to create a `SessionStorage` instance which takes care of the session persistence. In our case, we want to use a cookie-based session:


<pre>
  <code className="language-ts">
    {`
// services/authentication.ts
import { createCookieSessionStorage } from "@remix-run/node";

const sessionStorage = createCookieSessionStorage({
  cookie: {
    name: "logto-session",
    maxAge: 14 * 24 * 60 * 60,
    secrets: '${buildIdGenerator(12)()}', // Auto-generated secret
  },
});`}
  </code>
</pre>

</Step>

<Step
  title="Init LogtoClient"
  subtitle="1 step"
>

Use the `sessionStorage` created in the previous step to initialize LogtoClient:

<pre>
  <code className="language-ts">
    {`// app/services/authentication.ts

import { makeLogtoRemix } from "@logto/remix";

export const logto = makeLogtoRemix(
  {
    endpoint: '${props.endpoint}',${
      props.alternativeEndpoint ? ` // or "${props.alternativeEndpoint}"` : ''
    }
    appId: '${props.app.id}',
    appSecret: '${props.app.secret}',
    baseUrl: 'http://localhost:3000', // Change to your own base URL
  },
  { sessionStorage }
);`}
  </code>
</pre>

</Step>

<Step
  title="Mount auth routes"
  subtitle="3 routes"
>

The SDK ships with a convenient function that mounts the authentication routes: sign-in, sign-in callback and the sign-out route.

First, let’s enter your redirect URI. E.g. `http://localhost:3000/api/logto/sign-in-callback`.

<UriInputField name="redirectUris" />

Then mount 3 routes in your app:

```ts
// app/routes/api/logto/$action.ts

import { logto } from "../../../services/authentication";

export const loader = logto.handleAuthRoutes({
  "sign-in": {
    path: "/api/logto/sign-in",
    redirectBackTo: "/api/logto/callback", // The redirect URI just entered
  },
  "sign-in-callback": {
    path: "/api/logto/callback",
    redirectBackTo: "/",
  },
  "sign-out": {
    path: "/api/logto/sign-out",
    redirectBackTo: "/",
  },
});
```

As you can see, the mount process is configurable and you can adjust it for your particular route structure. The whole URL path structure can be customized via the passed configuration object.

When mounting the routes as described above, you can navigate your browser to `/api/logto/sign-in` and you should be redirected to your Logto instance where you have to authenticate then.

</Step>

<Step
  title="Get user profile"
  subtitle="and authentication context"
>

A typical use case is to fetch the _authentication context_ which contains information about the respective user. With that information, it is possible to decide if the user is authenticated or not. The SDK exposes a function that can be used in a Remix `loader` function:

```ts
// app/routes/index.tsx
import type { LogtoContext } from "@logto/remix";
import { LoaderFunction, json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";

import { logto } from "~/services/authentication";

type LoaderResponse = {
  readonly context: LogtoContext;
};

export const loader: LoaderFunction = async ({ request }) => {
  const context = await logto.getContext({ getAccessToken: false })(
    request
  );

  if (!context.isAuthenticated) {
    return redirect("/api/logto/sign-in");
  }

  return json<LoaderResponse>({ context });
};

const Home = () => {
  const data = useLoaderData<LoaderResponse>();

  return <div>Protected Route.</div>;
};
```

</Step>

</Steps>
