0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-30 20:33:54 -05:00

feat(console): remix guide (#4352)

* feat(console): remix guide

* fix: remove further readings and add redirect uri comment
This commit is contained in:
wangsijie 2023-08-17 12:00:07 +08:00 committed by GitHub
parent 7bbf3ae991
commit 49fb74ee31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 194 additions and 19 deletions

View file

@ -9,7 +9,6 @@ import nativeCapacitor from './native-capacitor/index';
import nativeFlutter from './native-flutter/index'; import nativeFlutter from './native-flutter/index';
import nativeIosSwift from './native-ios-swift/index'; import nativeIosSwift from './native-ios-swift/index';
import spaReact from './spa-react/index'; import spaReact from './spa-react/index';
import spaRemix from './spa-remix/index';
import spaVanilla from './spa-vanilla/index'; import spaVanilla from './spa-vanilla/index';
import spaVue from './spa-vue/index'; import spaVue from './spa-vue/index';
import { type Guide } from './types'; import { type Guide } from './types';
@ -24,6 +23,7 @@ import webNextAppRouter from './web-next-app-router/index';
import webOutline from './web-outline/index'; import webOutline from './web-outline/index';
import webPhp from './web-php/index'; import webPhp from './web-php/index';
import webPython from './web-python/index'; import webPython from './web-python/index';
import webRemix from './web-remix/index';
const guides: Readonly<Guide[]> = Object.freeze([ const guides: Readonly<Guide[]> = Object.freeze([
{ {
@ -68,12 +68,6 @@ const guides: Readonly<Guide[]> = Object.freeze([
Component: lazy(async () => import('./spa-react/README.mdx')), Component: lazy(async () => import('./spa-react/README.mdx')),
metadata: spaReact, metadata: spaReact,
}, },
{
id: 'spa-remix',
Logo: lazy(async () => import('./spa-remix/logo.svg')),
Component: lazy(async () => import('./spa-remix/README.mdx')),
metadata: spaRemix,
},
{ {
id: 'spa-vanilla', id: 'spa-vanilla',
Logo: lazy(async () => import('./spa-vanilla/logo.svg')), Logo: lazy(async () => import('./spa-vanilla/logo.svg')),
@ -152,6 +146,12 @@ const guides: Readonly<Guide[]> = Object.freeze([
Component: lazy(async () => import('./web-python/README.mdx')), Component: lazy(async () => import('./web-python/README.mdx')),
metadata: webPython, metadata: webPython,
}, },
{
id: 'web-remix',
Logo: lazy(async () => import('./web-remix/logo.svg')),
Component: lazy(async () => import('./web-remix/README.mdx')),
metadata: webRemix,
},
]); ]);
export default guides; export default guides;

View file

@ -1 +0,0 @@
## Replace this with actual guide

View file

@ -1,11 +0,0 @@
import { ApplicationType } from '@logto/schemas';
import { type GuideMetadata } from '../types';
const metadata: Readonly<GuideMetadata> = Object.freeze({
name: 'Remix',
description: 'Integrate your Remix application with Logto.',
target: ApplicationType.SPA,
});
export default metadata;

View file

@ -0,0 +1,175 @@
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, lets 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>

View file

@ -0,0 +1,12 @@
import { ApplicationType } from '@logto/schemas';
import { type GuideMetadata } from '../types';
const metadata: Readonly<GuideMetadata> = Object.freeze({
name: 'Remix',
description:
'Remix is a full stack web framework that lets you focus on the user interface and work back through web standards to deliver a fast, slick, and resilient user experience.',
target: ApplicationType.Traditional,
});
export default metadata;

View file

Before

Width:  |  Height:  |  Size: 947 B

After

Width:  |  Height:  |  Size: 947 B