Skip to content

Commit e032de5

Browse files
committed
feat: add Next.js server-side auth and HTTP-only cookie content
1 parent ea5dd67 commit e032de5

File tree

2 files changed

+323
-9
lines changed
  • src/pages
    • [platform]/build-a-backend/server-side-rendering
    • gen1/[platform]/build-a-backend/server-side-rendering/nextjs

2 files changed

+323
-9
lines changed

src/pages/[platform]/build-a-backend/server-side-rendering/index.mdx

+164-4
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ You can create an `amplifyServerUtils.ts` file under a `utils` folder in your co
5252

5353
For example, the `utils/amplifyServerUtils.ts` file may contain the following content:
5454

55-
```typescript
55+
```typescript title="src/utils/amplifyServerUtils.ts"
5656
import { createServerRunner } from '@aws-amplify/adapter-nextjs';
5757
import outputs from '@/amplify_outputs.json';
5858

@@ -108,7 +108,7 @@ If you're using the Next.js App Router, you can create a client component to con
108108

109109
`ConfigureAmplifyClientSide.ts`:
110110

111-
```typescript
111+
```typescript title="src/components/ConfigureAmplifyClientSide.tsx"
112112
'use client';
113113

114114
import { Amplify } from 'aws-amplify';
@@ -123,7 +123,7 @@ export default function ConfigureAmplifyClientSide() {
123123

124124
`layout.tsx`:
125125

126-
```jsx
126+
```jsx title="src/app/layout.tsx"
127127
import ConfigureAmplifyClientSide from '@/components/ConfigureAmplifyClientSide';
128128
import './globals.css';
129129

@@ -162,7 +162,7 @@ You can use the Amplify Auth category APIs to sign up and sign in your end users
162162

163163
You can use the `fetchAuthSession` API to check the auth sessions that are attached to the incoming requests in the middleware of your Next.js app to protect your routes. For example:
164164

165-
```typescript
165+
```typescript title="src/middleware.ts"
166166
import { fetchAuthSession } from 'aws-amplify/auth/server';
167167
import { NextRequest, NextResponse } from 'next/server';
168168
import { runWithAmplifyServerContext } from '@/utils/amplifyServerUtils';
@@ -215,6 +215,166 @@ In this example, if the incoming request is not associated with a valid user ses
215215

216216
</Callout>
217217

218+
### (Preview) Perform authentication on the server side and enable HTTP-only cookies
219+
220+
<Callout warning>
221+
222+
**NOTE:** Once you enable the server-side sign-in feature, auth tokens are stored in HTTP-only cookies and you may not change the HTTP-only attribute. Since these cookies are inaccessible from client-side scripts, you won’t be able to use any Amplify JS APIs on the client side. Therefore, you don’t need to configure Amplify on the client side.
223+
224+
</Callout>
225+
226+
**Prerequisites**
227+
228+
To authenticate users on the server side, you must enable either Amazon Cognito Managed Login or Hosted UI in your Amazon Cognito User Pool client.
229+
230+
231+
**Step 1: Specify the origin of your app in environment variables**
232+
233+
Add the following environment variables to your Next.js app. For example in a `.env` file:
234+
235+
```shell title=".env"
236+
AMPLIFY_APP_ORIGIN=https://myapp.com
237+
```
238+
239+
Ensure this environment variables is accessible in your Next.js app's server runtime.
240+
241+
**Step 2 - Export the `createAuthRouteHandlers` function**
242+
243+
`createAuthRouteHandlers` function is created by the `createServerRunner` function call when you configure Amplify for server-side usage. You can export this function from your `amplifyServerUtils.ts` file. You can also configure cookie attributes with the `runtimeOptions` parameter.
244+
245+
```typescript title="utils/amplifyServerUtils.ts"
246+
import { createServerRunner } from '@aws-amplify/adapter-nextjs';
247+
import config from '@/amplifyconfiguration.json';
248+
249+
export const {
250+
runWithAmplifyServerContext
251+
// highlight-start
252+
createAuthRouteHandlers,
253+
// highlight-end
254+
} = createServerRunner({
255+
config,
256+
// highlight-start
257+
runtimeOptions: {
258+
cookies: {
259+
domain: '.myapp.com', // making cookies available to all subdomains
260+
sameSite: 'strict',
261+
maxAge: 60 * 60 * 24 * 7 // 7 days
262+
}
263+
}
264+
// highlight-end
265+
});
266+
```
267+
268+
**Step 3 - Set up the Auth API routes**
269+
270+
Create an API route using the `createAuthRouteHandlers` function. For example:
271+
272+
<BlockSwitcher>
273+
<Block name="With the App router">
274+
```typescript title="src/app/api/auth/[slug].ts"
275+
import { createAuthRouteHandlers } from "@/amplifyServerUtils";
276+
277+
export const GET = createAuthRouteHandlers({
278+
redirectOnSignInComplete: "/home",
279+
redirectOnSignOutComplete: "/sign-in",
280+
});
281+
```
282+
</Block>
283+
<Block name="With Pages router">
284+
```typescript title="src/pages/api/auth/[slug].ts"
285+
import { createAuthRouteHandlers } from "@/amplifyServerUtils";
286+
287+
export default createAuthRouteHandlers({
288+
redirectOnSignInComplete: "/home",
289+
redirectOnSignOutComplete: "/sign-in",
290+
});
291+
```
292+
</Block>
293+
</BlockSwitcher>
294+
295+
With the above example, Amplify generates the following API routes:
296+
297+
| API Routes | What it does |
298+
| --------------------------------------------------- | ------------------------------------------------------------ |
299+
| `/api/auth/sign-up` | Upon navigating an end user to this route, they’ll be redirected to the Amazon Cognito Managed Login sign-up form. After sign-up and sign-in, they’ll be redirected back to the route specified by the `redirectOnSignInComplete` parameter. |
300+
| `/api/auth/sign-in` | Upon navigating an end user to this route, they’ll be redirected to the Amazon Cognito Managed Login sign-in form. After sign-in, they’ll be redirected back to the route specified by the `redirectOnSignInComplete` parameter. |
301+
| `/api/auth/sign-in?provider=<social-provider-name>` | Upon navigating an end user to this route, they’ll be redirected to Amazon Cognito Managed Login. Then, they’ll be redirected to the specified social provider sign-in page. After sign-in, they’ll be redirected back to the route specified by the `redirectOnSignOutComplete` parameter. |
302+
| `/api/auth/sign-out` | Upon navigating an end user to this route, the end user will be signed out and redirected to the route specified by the redirectOnSignOutComplete parameter. |
303+
| `/api/auth/sign-in-callback` | Amazon Cognito Managed Login redirects users back to this route after signing in. Amplify exchanges auth tokens and stores them as HTTP-only cookies in the browser cookie store. |
304+
| `/api/auth/sign-out-callback` | Amazon Cognito Managed Login redirects an end user back to this router after signing out, Amplify revokes access token and refresh token and removes token cookies from browser cookie store. |
305+
306+
307+
**Step 4 - Provide the redirect URLs to the Auth Resource in Amplify**
308+
309+
You can provide the callback API routes as the redirect URLs in the Auth resource configuration. For example:
310+
311+
```ts title="amplify/auth/resource.ts"
312+
export const auth = defineAuth({
313+
loginWith: {
314+
email: true,
315+
externalProviders: {
316+
google: {...},
317+
// highlight-start
318+
callbackUrls: ["https://myapp.com/api/auth/sign-in-callback"],
319+
logoutUrls: ["https://myapp.com/api/auth/sign-out-callback"],
320+
// highlight-end
321+
},
322+
},
323+
});
324+
```
325+
**Step 5 - Use Anchor link for initiating server-side authentication flows**
326+
327+
Use HTML anchor links to navigate users to the sign-in and sign-up routes. For example:
328+
329+
<BlockSwitcher>
330+
<Block name="Sign in button">
331+
```tsx title="src/components/SignInButton.tsx"
332+
export const SignInButton() {
333+
return (
334+
<a href="/api/auth/sign-in">
335+
Sign In
336+
</a>
337+
);
338+
}
339+
```
340+
</Block>
341+
<Block name="Sign in with Google button">
342+
```tsx title="src/components/SignInWithGoogleButton.tsx"
343+
export const SignInButton() {
344+
return (
345+
<a href="/api/auth/sign-in?provider=Google">
346+
Sign In
347+
</a>
348+
);
349+
}
350+
```
351+
</Block>
352+
<Block name="Sign up button">
353+
```tsx title="src/components/SignUpButton.tsx"
354+
export const SignInButton() {
355+
return (
356+
<a href="/api/auth/sign-up">
357+
Sign In
358+
</a>
359+
);
360+
}
361+
```
362+
</Block>
363+
<Block name="Sign out button">
364+
```tsx title="src/components/SignOutButton.tsx"
365+
export const SignInButton() {
366+
return (
367+
<a href="/api/auth/sign-out">
368+
Sign In
369+
</a>
370+
);
371+
}
372+
```
373+
</Block>
374+
</BlockSwitcher>
375+
376+
When an end user clicks on the buttons above, a corresponding server-side authentication flow will be initiated.
377+
218378
## Calling Amplify category APIs on the server side
219379

220380
For the **Auth** categories to use Amplify APIs on the server in your Next.js app, you will need to:

0 commit comments

Comments
 (0)