Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8931776

Browse files
authoredMay 19, 2025··
feat(console): add remix guide (#7384)
1 parent e8df19b commit 8931776

File tree

6 files changed

+195
-0
lines changed

6 files changed

+195
-0
lines changed
 

‎packages/console/src/assets/docs/guides/index.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import webOutline from './web-outline/index';
3838
import webPassport from './web-passport/index';
3939
import webPhp from './web-php/index';
4040
import webPython from './web-python/index';
41+
import webRemix from './web-remix';
4142
import webRuby from './web-ruby/index';
4243
import webSveltekit from './web-sveltekit/index';
4344
import webWordpress from './web-wordpress/index';
@@ -108,6 +109,14 @@ export const guides: Readonly<Guide[]> = Object.freeze([
108109
Component: safeLazy(async () => import('./web-sveltekit/README.mdx')),
109110
metadata: webSveltekit,
110111
},
112+
{
113+
order: 1.2,
114+
id: 'web-remix',
115+
Logo: safeLazy(async () => import('./web-remix/logo.svg?react')),
116+
DarkLogo: safeLazy(async () => import('./web-remix/logo-dark.svg?react')),
117+
Component: safeLazy(async () => import('./web-remix/README.mdx')),
118+
metadata: webRemix,
119+
},
111120
{
112121
order: 1.3,
113122
id: 'spa-vue',
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import NpmLikeInstallation from '@/mdx-components/NpmLikeInstallation';
2+
import { generateStandardSecret } from '@logto/shared/universal';
3+
import Steps from '@/mdx-components/Steps';
4+
import Step from '@/mdx-components/Step';
5+
import Checkpoint from '../../fragments/_checkpoint.md';
6+
import RedirectUrisWeb, { defaultBaseUrl } from '../../fragments/_redirect-uris-web.mdx';
7+
8+
<Steps>
9+
10+
<Step
11+
title="Installation"
12+
subtitle="Install Logto SDK"
13+
>
14+
15+
<NpmLikeInstallation packageName="@logto/remix" />
16+
17+
</Step>
18+
19+
<Step
20+
title="Init LogtoClient"
21+
>
22+
23+
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:
24+
25+
<Code title="services/auth.server.ts" className="language-ts">
26+
{`import { createCookieSessionStorage } from '@remix-run/node';
27+
import { makeLogtoRemix } from '@logto/remix';
28+
29+
const sessionStorage = createCookieSessionStorage({
30+
cookie: {
31+
name: 'logto-session',
32+
maxAge: 14 * 24 * 60 * 60,
33+
secrets: '${generateStandardSecret()}', // Auto-generated 32 digit secret
34+
},
35+
});
36+
37+
export const logto = makeLogtoRemix(
38+
{
39+
endpoint: '${props.endpoint}',
40+
appId: '${props.app.id}',
41+
appSecret: '${props.secrets[0]?.value ?? props.app.secret}',
42+
baseUrl: '${defaultBaseUrl}', // Change to your own base URL
43+
},
44+
{ sessionStorage }
45+
);`}
46+
</Code>
47+
48+
</Step>
49+
50+
<Step
51+
title="Configure redirect URIs"
52+
subtitle="2 URIs"
53+
>
54+
55+
<RedirectUrisWeb defaultRedirectUri={`${defaultBaseUrl}api/logto/callback`} />
56+
57+
</Step>
58+
59+
<Step title="Mounting authentication routes">
60+
61+
The SDK ships with a convenient function that mounts the authentication routes: sign-in, sign-in callback and the sign-out route. Create a file `routes/api.logto.$action.ts`
62+
63+
```ts title="routes/api.logto.$action.ts"
64+
import { logto } from '../services/auth.server';
65+
66+
export const loader = logto.handleAuthRoutes({
67+
'sign-in': {
68+
path: '/api/logto/sign-in',
69+
redirectBackTo: '/api/logto/callback',
70+
},
71+
'sign-in-callback': {
72+
path: '/api/logto/callback',
73+
redirectBackTo: '/',
74+
},
75+
'sign-out': {
76+
path: '/api/logto/sign-out',
77+
redirectBackTo: '/',
78+
},
79+
'sign-up': {
80+
path: '/api/logto/sign-up',
81+
redirectBackTo: '/api/logto/callback',
82+
},
83+
});
84+
```
85+
86+
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.
87+
88+
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.
89+
90+
</Step>
91+
92+
<Step
93+
title="Implement sign-in and sign-out"
94+
>
95+
96+
We have prepared the authentication routes, now let's implement the sign-in and sign-out buttons in your home page. We need to redirect the user to the sign-in or sign-out route when needed. To help with this, use `loader` to fetch authentication status from Logto client.
97+
98+
```tsx title="/app/routes/_index.tsx"
99+
import { type LogtoContext } from '@logto/remix';
100+
import { type LoaderFunction } from '@remix-run/node';
101+
import { json, Link, useLoaderData } from '@remix-run/react';
102+
103+
import { logto } from '../services/auth.server';
104+
105+
type LoaderResponse = {
106+
readonly context: LogtoContext;
107+
};
108+
109+
export const loader: LoaderFunction = async ({ request }) => {
110+
const context = await logto.getContext({ getAccessToken: false })(request);
111+
112+
return json<LoaderResponse>({ context });
113+
};
114+
115+
const Home = () => {
116+
const { context } = useLoaderData<LoaderResponse>();
117+
const { isAuthenticated, claims } = context;
118+
119+
return (
120+
<div>
121+
<h1>Remix Sample</h1>
122+
{isAuthenticated ? (
123+
<div>
124+
<p>Hello {claims?.email ?? claims?.name ?? claims?.sub}</p>
125+
<form action="/api/logto/sign-out" method="get">
126+
<button type="submit">Sign Out</button>
127+
</form>
128+
<p>
129+
<Link to="/user-info">Example of fetching user info</Link>
130+
</p>
131+
<p>
132+
<Link to="/access-token">Example of fetching access token</Link>
133+
</p>
134+
</div>
135+
) : (
136+
<form action="/api/logto/sign-in" method="get">
137+
<button type="submit">Sign In</button>
138+
</form>
139+
)}
140+
</div>
141+
);
142+
};
143+
144+
export default Home;
145+
```
146+
147+
</Step>
148+
149+
<Step
150+
title="Checkpoint: Test your application"
151+
>
152+
153+
<Checkpoint />
154+
155+
</Step>
156+
157+
</Steps>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"order": 1.2
3+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { ApplicationType } from '@logto/schemas';
2+
3+
import { type GuideMetadata } from '../types';
4+
5+
const metadata: Readonly<GuideMetadata> = Object.freeze({
6+
name: 'Remix',
7+
description:
8+
'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.',
9+
target: ApplicationType.Traditional,
10+
sample: {
11+
repo: 'js',
12+
path: 'packages/remix-sample',
13+
},
14+
fullGuide: 'remix',
15+
});
16+
17+
export default metadata;
Lines changed: 5 additions & 0 deletions
Loading
Lines changed: 4 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)
Please sign in to comment.