サーバー側レンダリング
このガイドでは、Next.js のサーバー側ランタイムから Amplify Auth および Data API を使用する方法について説明します。
始める前に:
Amplify Next.js アダプターをインストールする
Amplify API をサーバー側で使用するには、Amplify ライブラリに加えて Amplify Next.js アダプターをインストールする必要があります:
npm add aws-amplify @aws-amplify/adapter-nextjsNext.js で Amplify を設定する
Next.js アプリケーションのサーバー側で Amplify API を使用するために runWithAmplifyServerContext 関数を作成する必要があります。
コードベース内の utils フォルダ下に amplifyServerUtils.ts ファイルを作成できます。このファイルでは、Amplify CLI によって生成される amplify_outputs.json ファイルから Amplify バックエンド出力をインポートし、createServerRunner 関数を使用して runWithAmplifyServerContext 関数を作成します。
例えば、utils/amplifyServerUtils.ts ファイルは次のコンテンツを含むことができます:
import { createServerRunner } from '@aws-amplify/adapter-nextjs';import outputs from '@/amplify_outputs.json';
export const { runWithAmplifyServerContext } = createServerRunner({ config: outputs});エクスポートされた runWithAmplifyServerContext 関数を使用して、分離されたリクエストコンテキスト内で Amplify API を呼び出すことができます。例については、サーバー側での Amplify カテゴリ API の呼び出し セクションを参照してください。
Next.js アプリケーションのクライアント側で Amplify ライブラリを使用する場合、シングルページアプリケーションで Amplify を使用する場合と同じように Amplify.configure を呼び出すことで Amplify を設定する必要があります。
'use client';
import outputs from '@/amplify_outputs.json';import { Amplify } from 'aws-amplify';
Amplify.configure(outputs, { ssr: true // Next.js で Amplify を使用する場合は必須});
export default function RootLayoutThatConfiguresAmplifyOnTheClient({ children}: { children: React.ReactNode;}) { return children;}詳細を学ぶNext.js App Router アプリケーションで Amplify を設定する
Next.js App Router を使用している場合、Amplify を設定するクライアントコンポーネントを作成してルートレイアウトにインポートできます。
ConfigureAmplifyClientSide.ts:
'use client';
import { Amplify } from 'aws-amplify';import outputs from '../amplify_outputs.json';
Amplify.configure(outputs, { ssr: true });
export default function ConfigureAmplifyClientSide() { return null;}layout.tsx:
import ConfigureAmplifyClientSide from '@/components/ConfigureAmplifyClientSide';import './globals.css';
import type { Metadata } from 'next';
export const metadata: Metadata = { title: 'Create Next App', description: 'Generated by create next app',};
export default function RootLayout({ children,}: { children: React.ReactNode;}) { return ( <html lang="en"> <body className="container pb-6"> <> <ConfigureAmplifyClientSide /> {children} </> </body> </html> );}Next.js サーバー側ランタイムを使用した認証
(実験的) サーバー側で認証を実行し、HttpOnly クッキーを有効にする
Next.js アプリケーションでサーバー側認証フローを有効にするには、追加の設定が必要です。
ステップ 1 - 環境変数でアプリのオリジンを指定する
Next.js アプリケーションに次の環境変数を追加します。例えば .env ファイルで:
AMPLIFY_APP_ORIGIN=https://myapp.comこの環境変数が Next.js アプリケーションのサーバーランタイムでアクセス可能であることを確認します。
ステップ 2 - createAuthRouteHandlers 関数をエクスポートする
createAuthRouteHandlers 関数は、サーバー側使用のために Amplify を設定する際に createServerRunner 関数の呼び出しによって作成されます。この関数を amplifyServerUtils.ts ファイルからエクスポートできます。runtimeOptions パラメータを使用してクッキー属性を設定することもできます。
import { createServerRunner } from '@aws-amplify/adapter-nextjs';import outputs from '@/amplify_outputs.json';
export const { runWithAmplifyServerContext, createAuthRouteHandlers,} = createServerRunner({ config: outputs, runtimeOptions: { cookies: { domain: '.myapp.com', // すべてのサブドメインでクッキーを利用可能にする sameSite: 'strict', maxAge: 60 * 60 * 24 * 7 // 7 日間 } }});ステップ 3 - Auth API ルートを設定する
createAuthRouteHandlers 関数を使用して API ルートを作成します。例:
import { createAuthRouteHandlers } from "@/utils/amplifyServerUtils";
export const GET = createAuthRouteHandlers({ redirectOnSignInComplete: "/home", redirectOnSignOutComplete: "/sign-in",});import { createAuthRouteHandlers } from "@/utils/amplifyServerUtils";
export default createAuthRouteHandlers({ redirectOnSignInComplete: "/home", redirectOnSignOutComplete: "/sign-in",});上記の例では、Amplify は次の API ルートを生成します:
| API ルート | 機能 |
|---|---|
/api/auth/sign-up | エンドユーザーをこのルートにナビゲートすると、Amazon Cognito Managed Login サインアップフォームにリダイレクトされます。サインアップとサインインの後、/api/auth/sign-in-callback ルートにリダイレクトされます。 |
/api/auth/sign-in | エンドユーザーをこのルートにナビゲートすると、Amazon Cognito Managed Login サインインフォームにリダイレクトされます。サインイン後、/api/auth/sign-in-callback ルートにリダイレクトされます。 |
/api/auth/sign-in?provider=<social-provider-name> | エンドユーザーをこのルートにナビゲートすると、まず Amazon Cognito Managed Login にリダイレクトされ、次に指定されたソーシャルプロバイダーのサインインページにリダイレクトされます。サインイン後、/api/auth/sign-in-callback ルートにリダイレクトされます。 |
/api/auth/sign-out | エンドユーザーをこのルートにナビゲートすると、エンドユーザーはサインアウトされ、/api/auth/sign-out-callback ルートにリダイレクトされます。 |
/api/auth/sign-in-callback | Amazon Cognito Managed Login はサインイン後、エンドユーザーをこのルートにリダイレクトします。Amplify は認証トークンを交換し、ブラウザークッキーストア内に HttpOnly クッキーとして保存し、redirectOnSignInComplete パラメータで指定されたルートにエンドユーザーをリダイレクトします。 |
/api/auth/sign-out-callback | Amazon Cognito Managed Login はサインアウト後、エンドユーザーをこのルートにリダイレクトします。Amplify はアクセストークンとリフレッシュトークンを無効化し、ブラウザークッキーストアからトークンクッキーを削除してから、redirectOnSignOutComplete パラメータで指定されたルートにエンドユーザーをリダイレクトします。 |
Amazon Cognito Managed Login ページの言語をカスタマイズするには、/api/auth/sign-in ルートと /api/auth/sign-up ルートに lang クエリパラメータを追加できます。例: /api/auth/sign-in?lang=fr。サポートされている言語の詳細については、Managed login ローカライズドキュメント を参照してください。
ステップ 4 - リダイレクト URL を Amplify の Auth リソースに提供する
コールバック API ルートをAuth リソース設定のリダイレクト URL として提供できます。例:
export const auth = defineAuth({ loginWith: { email: true, externalProviders: { callbackUrls: ["https://myapp.com/api/auth/sign-in-callback"], logoutUrls: ["https://myapp.com/api/auth/sign-out-callback"], }, },});これにより、Amazon Cognito Hosted UI はサーバー側認証フローをサポートできます。最新の Amazon Cognito Managed Login ブランディングにアップグレードして、サインインおよびサインアップページをカスタマイズできます。詳細については、Amazon Cognito ユーザープール Managed Login を参照してください。
ステップ 5 - サーバー側認証フローを開始するためにアンカーリンクを使用する
HTML アンカーリンクを使用してユーザーをサインインおよびサインアップルートにナビゲートします。例:
export default function SignInButton() { return ( <a href="/api/auth/sign-in"> Sign In </a> );}export default function SignInWithGoogleButton() { return ( <a href="/api/auth/sign-in?provider=Google"> Sign In with Google </a> );}export default function SignUpButton() { return ( <a href="/api/auth/sign-up"> Sign Up </a> );}export default function SignOutButton() { return ( <a href="/api/auth/sign-out"> Sign Out </a> );}エンドユーザーが上記のボタンをクリックすると、対応するサーバー側認証フローが開始されます。
Next.js ミドルウェアでユーザーセッションを検証する
fetchAuthSession API を使用して、Next.js アプリケーションのミドルウェアで受信リクエストに添付されている認証セッションを確認してルートを保護できます。例:
import { fetchAuthSession } from 'aws-amplify/auth/server';import { NextRequest, NextResponse } from 'next/server';import { runWithAmplifyServerContext } from '@/utils/amplifyServerUtils';
export async function middleware(request: NextRequest) { const response = NextResponse.next();
const authenticated = await runWithAmplifyServerContext({ nextServerContext: { request, response }, operation: async (contextSpec) => { try { const session = await fetchAuthSession(contextSpec); return ( session.tokens?.accessToken !== undefined && session.tokens?.idToken !== undefined ); } catch (error) { console.log(error); return false; } } });
if (authenticated) { return response; }
return NextResponse.redirect(new URL('/sign-in', request.url));}
export const config = { matcher: [ /* * 次で始まるもの以外のすべてのリクエストパスと一致させます: * - api (API ルート) * - _next/static (静的ファイル) * - _next/image (画像最適化ファイル) * - favicon.ico (ファビコンファイル) */ '/((?!api|_next/static|_next/image|favicon.ico|sign-in).*)' ]};この例では、受信リクエストが有効なユーザーセッションに関連付けられていない場合、リクエストは /sign-in ルートにリダイレクトされます。
サーバー側での Amplify カテゴリ API の呼び出し
Next.js アプリケーションのサーバーで Amplify API を使用するための Auth カテゴリについては、以下を行う必要があります:
/serverサブパスから API をインポートします。@aws-amplify/adapter-nextjsからエクスポートされたcreateServerRunner関数を呼び出すことで作成されたrunWithAmplifyServerContextヘルパー関数を使用して、分離されたサーバーコンテキストで Amplify API を呼び出します。
GraphQL API カテゴリについては、サーバー側ランタイムからデータに接続 を参照してください。
Next.js App Router の使用
React サーバーコンポーネントでの動的レンダリング
動的レンダリングは、受信リクエストから抽出されたユーザーセッションに基づいています。
import { cookies } from 'next/headers';import { getCurrentUser } from 'aws-amplify/auth/server';import { runWithAmplifyServerContext } from '@/utils/amplifyServerUtils';
// このページは常にリクエストごとに動的にレンダリングされますexport const dynamic = 'force-dynamic';
export default async function AuthGetCurrentUserServer() { try { const currentUser = await runWithAmplifyServerContext({ nextServerContext: { cookies }, operation: (contextSpec) => getCurrentUser(contextSpec) });
return ( <p>{`Hello, ${currentUser.username}`}</p> ); } catch (error) { console.error(error); return <p>Something went wrong...</p>; }}React サーバーコンポーネントでの静的レンダリング
静的レンダリングはユーザーセッションを必要としないため、nextServerContext パラメータを null として指定できます。これはいくつかの使用例で便利です。例えば、Storage API をゲストアクセス (バックエンドで有効にしている場合) で使用する場合です。
import { getUrl } from 'aws-amplify/storage/server';import Image from 'next/image';import { runWithAmplifyServerContext } from '@/utils/amplifyServerUtils';
// このページを 60 分ごとに再レンダリングしますexport const revalidate = 60 * 60; // 秒単位
export default async function StaticallyRenderedPage() { try { const splashUrl = await runWithAmplifyServerContext({ nextServerContext: null, operation: (contextSpec) => getUrl(contextSpec, { key: 'splash.png' }) });
return ( <Image src={splashUrl.url.toString()} alt="Splash Image" width={500} height={500} /> ); } catch (error) { console.error(error); return <p>Something went wrong...</p>; }}ルートハンドラーで
ルートハンドラーは GET /apis/get-current-user を有効にする API ルートを実装する必要があります。
import { getCurrentUser } from 'aws-amplify/auth/server';import { cookies } from 'next/headers';import { NextResponse } from 'next/server';import { runWithAmplifyServerContext } from '@/utils/amplifyServerUtils';
export async function GET() { const user = await runWithAmplifyServerContext({ nextServerContext: { cookies }, operation: (contextSpec) => getCurrentUser(contextSpec) });
return NextResponse.json({ user });}/apis/get-current-user を呼び出すと、現在サインインしているユーザーの user データを含むペイロードが返されます。
Next.js Pages Router の使用
getServerSideProps で
次の例は、リクエストから現在のユーザーデータを抽出し、プロップを通じてページ React コンポーネントに提供します。
export const getServerSideProps: GetServerSideProps = async ({ req, res }) => { const currentUser = await runWithAmplifyServerContext({ nextServerContext: { request: req, response: res }, operation: (contextSpec) => getCurrentUser(contextSpec) });
return { props: { currentUser } };};getStaticProps で
App Router での静的レンダリングと同様に、nextServerContext パラメータの値として null を渡して、ゲストアクセスで Amplify Storage API を使用できます。
export async function getStaticProps() { const splashUrl = await runWithAmplifyServerContext({ nextServerContext: null, operation: (contextSpec) => getUrl(contextSpec, { key: 'splash.png' }) });
return { props: { imageUrl: splashUrl.url.toString() }, revalidate: (splashUrl.expiresAt.getTime() - Date.now()) / 1000 // 秒単位 };}Next.js サーバー側使用でサポートされている API
サーバーで使用をサポートするすべての API は、aws-amplify/<category>/server サブパスからエクスポートされます。サーバー側の使用例については、これらの API を使用する必要があります。
| カテゴリ | API | サーバー (Node.js) Amplify Hosting/Vercel | Vercel Edge Runtime (ミドルウェア) |
|---|---|---|---|
| Auth | fetchAuthSession | ✅ | ✅ |
| Auth | fetchUserAttributes | ✅ | ✅ |
| Auth | getCurrentUser | ✅ | ✅ |
| Data | generateServerClientUsingCookies | ✅ | |
| Data | generateServerClientUsingReqRes | ✅ | |
| Storage | getUrl | ✅ | |
| Storage | getProperties | ✅ | |
| Storage | list | ✅ | |
| Storage | remove | ✅ | |
| Storage | copy | ✅ |