『何でも見てやろう』(小田実)の精神で、自分でもコードを書いてみる編集者・長尾です。
KODANSHAtech LLC.でゼネラルマネージャーやってます。
エンジニアのみなさん大募集中なので、メディアやコンテンツ開発に興味のある方はぜひ〜。
実はAuth0 Ambassadorもやってます。
さて、今回はとっても便利なServerless Next.js1に、とっても便利なIdaaS、Auth0を組み合わせて、簡単便利にサーバレスな会員制サイトを作れそうということで、実験してみた一連の流れをご紹介してみます2!
少し書いてみたら結構ボリューミーだったので、以下のように3回に分けようと思います。
- セッティングとユーザーのログイン状態を取り回せる基本的なページの構築
- SSR時にユーザー情報を必要とすることで、そもそも非ログインユーザーには表示できないページを作る方法
- 外部のAPIにauth tokenを送って検証させる方法
元ネタは以下になります。
とくにauth0/nextjs-auth0
のexampleをなぞる部分が多くなっています。
やってみた記事なので、変なところがあったら、ぜひご指摘ください…。
前提
serverless/Auth0など利用するリソースはこちら(折りたたんでいます)
- node
- npm
- serverless
このあたりまでは、すでに利用されている方向けです。
Go Serverless!
も使っていきます。
そしてもちろん、IdaaSとしては、我らがAuth0です。
serverlessでもいろいろなクラウドサービス(SaaS)が利用できますが、本記事ではAWSを利用する形で考えていきます。
Serverless Next.js
ServerlessBlog: https://www.serverless.com/blog/serverless-nextjs/
GitHub: https://github.com/danielcondemarin/serverless-next.js
クラウドリソースをベースに、サーバを必要とせず、サービスを提供できるServerless Framework。
AWSコンソールをポチポチやらなくても、 serverless.yml
に必要な記述をすれば、 CloudFormation
によってリソースが立ち上がってくれる、とっても便利なframeworkですよね。
そんなserverlessの世界をさらに豊かにするために作られたのが、 serverless component
。
ごくかいつまんでいうと、serverlessで構築されるサービスを、 Component
という塊として定義し、再利用可能にしたブロックのようなものです。
参考: https://www.serverless.com/blog/what-are-serverless-components-how-use/
Serverless Next.jsは、簡単設定でNext.jsのserverless mode
が立ち上がるというすぐれものです。
筆者は初学者なので、充実した解説は他の方にお願いするとして、大きな特徴だと感じたのは、 Serverless Next.jsがLambda@Edge
でホスティングされるという点です。そのため、
-
pages
のServerSideRendering(SSR)がLambda@Edge上で行われる。 - APIも同じくLambda@Edgeで取り回され、実行される。
これはつまり、 CloudFront
のEdgeですべてが行われるということで、もはや特定のregion
に依存しない形でNext.jsを利用したサービスを提供できることを意味します(この点は、後述する設定の仕方に少し影響しています)。
余談ですが、KODANSHAtech LLC.のサイトもServerless Next.jsで作ってみたサイトです。
Auth0
"Identity is Complex. Deal with it."
いわゆるログイン機能、あるいは認証認可の機能を提供するサービスといえば、 Cognito
やFirebase Authentication
など、さまざまな選択肢があります。
そんな中、認証認可基盤であることに完全に特化することで、APIを通じた「疎」な世界観にマッチしたIdaaSとして注目されているのが、Auth0です。
どんなサービスにも組み込みやすく、ソーシャルログインやOIDC、SAMLへの対応も簡単、しかもドキュメンテーションが非常に充実していて、何をどう取り回せばセキュアなID管理ができるのか、すぐに調べられるのも大きな特徴でしょう。
この記事の末尾で触れたいと思いますが、Next.jsをserverlessで利用する場面では、やはりAuth0が「疎」なIdaaSを志向していることが、強みを発揮すると思います。
いろいろ書きたくなるのですが、「やってみた」パートに早く移るため、詳細は下記のリンクを示すことで代えさせていただきます!
- (少し古いけど基本がよくわかる)認証プラットフォーム Auth0 とは?
- Classmethod諏訪さんのところのDevelopers.IOにも記事が多数
Getting Started
今回は、Serverless Next.jsにAuth0 Next.jsの公式exampleを組み合わせて、ログイン機能を実現し、ユーザー情報を表示させるところまでを試してみます。
まずは、Serverless Next.jsの準備からです。
Preparing serverless-next.js
mkdir my-project
cd my-project
npm init -y
npm install --save-dev serverless-next.js
touch .env
touch serverless.yml
serverless.yml
には、よくServerless Frameworkで書くようにprovider
とかresouces
といったことを列記する必要はなく、下記の記述だけで事足ります。
myNextApplication:
component: serverless-next.js
実際の利用の場面では、サービスを独自のドメインで公開することになると思います。
その場合、Route53
を利用して設定するドメインの指定をここに記述します。
myNextApplication:
component: serverless-next.js
inputs:
domain: "example.com"
サブドメインを利用する場合は、次のようになります。
myNextApplication:
component: serverless-next.js
inputs:
domain: ["sub","example.com"]
ここで注意が必要なのは、ドメインのCertificate
についてです。
利用したいドメインについての証明書は、deployの前に取得しておく必要があります。
しかし、上述したように、Serverless Next.jsはLambda@Edgeでホスティングされるため、
もはや特定の
region
に依存しない形でNext.jsを利用したサービスを提供できる
ものになっています。
そのため、利用するドメインに対するcertificateは、Lambda@Edgeが利用可能なus-east-1
で取得しておく必要があります。
AWSのCertificate Manager
で証明書を取得するときは、リージョンに注意してください。
.env
には、AWSのcredentialsを入れておきます。適宜、ご利用のものに入れ替えてください。
AWS_ACCESS_KEY_ID=accesskey
AWS_SECRET_ACCESS_KEY=accesssecret
これはserverless-next.jsのために必要だという設定ではありませんが、あとで利用するために、package.json
のscripts
は以下のようにしておきます。
{
...
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start -p $PORT",
"test": "echo \"Error: no test specified\" && exit 1"
},
...
}
Preparing Auth0 Application
アカウントの作成などは、前述した他の記事をご参照ください。
ここでは、Auth0に新しいtenant
を作り、Applications
のタブを開きます。
Domain/ClientID/ClientSecretの取得方法や設定など。画像が多いので折りたたんでいます。Click Here to Unfold!
+CREATE APPLICATION
で、Regular Web Applications
を選択し、新しいApplicationを作ります。
作ったApplicationのSettings
タブで、以下の情報が確認できるので、これをメモしておきます。
- Domain
- Client ID
- Client Secret
また、Settings
の最下部に、Show Advanced Settings
がありますので、ここを開いて、OAuth
のタブを確認しておきましょう。
JsonWebToken Signiture Algorithm
はRS256
、OIDC Conformant
はonになっている必要があります。
次に、ローカルでNext.jsのアプリを立ち上げて試す場合に、Auth0が機能するように、Application URLs
のセクションに、次のように記入しておきます。
- Allowed Callback URLs: http://localhost:3000/api/callback
- Allowed Logout URLs: http://localhost:3000/
Preparing Next.js Application with Auth0
次に、Next.jsとAuth0でアプリケーションを作っていきます。
npm install --save next react react-dom
touch next.config.js
next.config.js
には、以下の記述を入れます。
module.exports = {
target: "serverless"
};
今回は、Next.jsで簡単にAuth0が使えるauth0/nextjs-auth0
を利用していきます。
https://github.com/auth0/nextjs-auth0
npm install --save @auth0/nextjs-auth0 dotenv isomorphic-unfetch
mkdir lib
touch lib/auth0.js
touch lib/auth0-config.js
ちょっとディレクトリの命名に迷うのですが、今回はlib
の中にauth0.js
を作ります(ちなみに公式GitHubではREADMEの解説でutil
、exampleで使われている実際のディレクトリはlib
)。
auth0.js
は以下のように記述します。
公式のままだと、場合によって書き直して使わないといけないので、少し変更していますが、お好みにあわせてどうぞ。
import { initAuth0 } from '@auth0/nextjs-auth0';
import config from './auth0-config';
const auth0 = (opt) => {
opt = opt || {};
let params = {
domain: config.AUTH0_DOMAIN,
clientId: config.AUTH0_CLIENT_ID,
clientSecret: config.AUTH0_CLIENT_SECRET,
scope: opt.scope || config.AUTH0_SCOPE,
redirectUri: opt.redirectUri || config.REDIRECT_URI,
postLogoutRedirectUri: opt.postLogoutRedirectUri || config.POST_LOGOUT_REDIRECT_URI,
session: {
// The secret used to encrypt the cookie.
cookieSecret: config.SESSION_COOKIE_SECRET,
// The cookie lifetime (expiration) in seconds. Set to 8 hours by default.
cookieLifetime: opt.session && opt.session.cookieLifetime ? opt.session.cookieLifetime : config.SESSION_COOKIE_LIFETIME,
// (Optional) The cookie domain this should run on. Leave it blank to restrict it to your domain.
// cookieDomain: config.SESSION_COOKIE_DOMAIN, //今回は使わないでおきます。
// (Optional) SameSite configuration for the session cookie. Defaults to 'lax', but can be changed to 'strict' or 'none'. Set it to false if you want to disable the SameSite setting.
cookieSameSite: 'lax',
// (Optional) Store the id_token in the session. Defaults to false.
storeIdToken: opt.session && opt.session.storeIdToken ? opt.session.storeIdToken : false,
// (Optional) Store the access_token in the session. Defaults to false.
storeAccessToken: opt.session && opt.session.storeAccessToken ? opt.session.storeAccessToken : false,
// (Optional) Store the refresh_token in the session. Defaults to false.
storeRefreshToken: opt.session && opt.session.storeRefreshToken ? opt.session.storeRefreshToken : false
},
oidcClient: {
// (Optional) Configure the timeout in milliseconds for HTTP requests to Auth0.
httpTimeout: opt.oidcClient && opt.oidcClient.httpTimeout ? opt.oidcClient.httpTimeout : 2500,
// (Optional) Configure the clock tolerance in milliseconds, if the time on your server is running behind.
clockTolerance: opt.oidcClient && opt.oidcClient.clockTolerance ? opt.oidcClient.clockTolerance : 10000
}
};
if(opt.aud){
params['audience'] = config.AUDIENCE
}
return initAuth0(params);
};
export default auth0;
auth0-config.js
は、公式exampleにあわせ、次のようにしています。
if (typeof window === 'undefined') {
/**
* サーバーサイドで使われるセッティング
*/
module.exports = {
AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID,
AUTH0_CLIENT_SECRET: process.env.AUTH0_CLIENT_SECRET,
AUTH0_SCOPE: process.env.AUTH0_SCOPE,
AUTH0_DOMAIN: process.env.AUTH0_DOMAIN,
REDIRECT_URI: process.env.REDIRECT_URI,
POST_LOGOUT_REDIRECT_URI: process.env.POST_LOGOUT_REDIRECT_URI,
SESSION_COOKIE_SECRET: process.env.SESSION_COOKIE_SECRET,
SESSION_COOKIE_LIFETIME: process.env.SESSION_COOKIE_LIFETIME,
//SESSION_COOKIE_DOMAIN: process.env.SESSION_COOKIE_DOMAIN //指定したい場合。以下略。
AUDIENCE: process.env.AUDIENCE
};
} else {
/**
* クライアントサイドに露出するセッティング
*/
module.exports = {
AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID,
AUTH0_SCOPE: process.env.AUTH0_SCOPE,
AUTH0_DOMAIN: process.env.AUTH0_DOMAIN,
REDIRECT_URI: process.env.REDIRECT_URI,
POST_LOGOUT_REDIRECT_URI: process.env.POST_LOGOUT_REDIRECT_URI
};
}
次に、next.config.js
のenv
で情報を読み込みます。
const dotenv = require('dotenv');
dotenv.config();
module.exports = {
target: "serverless",
env: {
AUTH0_DOMAIN: process.env.AUTH0_DOMAIN,
AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID,
AUTH0_CLIENT_SECRET: process.env.AUTH0_CLIENT_SECRET,
AUTH0_SCOPE: 'openid profile',
REDIRECT_URI: process.env.REDIRECT_URI || 'http://localhost:3000/api/callback',
POST_LOGOUT_REDIRECT_URI: process.env.POST_LOGOUT_REDIRECT_URI || 'http://localhost:3000/',
SESSION_COOKIE_SECRET: process.env.SESSION_COOKIE_SECRET,
SESSION_COOKIE_LIFETIME: 7200, // 2 hours
AUDIENCE: process.env.AUDIENCE
}
};
最後に各種の情報を.env
に追記します。
先ほど、Auth0のコンソールをみながらメモした情報です。
AWS_ACCESS_KEY_ID=accesskey
AWS_SECRET_ACCESS_KEY=accesssecret
AUTH0_DOMAIN=yourdomain.auth0.com
AUTH0_CLIENT_ID=************
AUTH0_CLIENT_SECRET=**************
REDIRECT_URI=*************
POST_LOGOUT_REDIRECT_URI=*********
SESSION_COOKIE_SECRET=************ //40文字以上のランダム文字列
AUDIENCE=****** //これはのちにAPIの保護で使うもので、今回はあまり関係ありません
テストの段階では、localhost:3000
で動かすため、REDIRECT_URI
とPOST_LOGOUT_REDIRECT_URI
は.env
から削除しておいてください。
Preparing APIs
次に、ログインやログアウトを取り回すAPIをpages/api
に作っていきます。
mkdir pages
mkdir pages/api
touch pages/api/{login.js,logout.js,callback.js,me.js}
lib/auth0
の作りを公式とは少し変えていますので、それにあわせて変更しています。
Auth0のライブラリが細かいところをマネージしてくれるので、ひとつひとつは非常にシンプルですね。
import auth0 from '../../lib/auth0';
export default async function login(req, res) {
try {
await auth0().handleLogin(req, res);
} catch (error) {
console.error(error);
res.status(error.status || 500).end(error.message);
}
}
import auth0 from '../../lib/auth0';
export default async function logout(req, res) {
try {
await auth0().handleLogout(req, res);
} catch (error) {
console.error(error);
res.status(error.status || 500).end(error.message);
}
}
import auth0 from '../../lib/auth0';
export default async function callback(req, res) {
try {
await auth0().handleCallback(req, res);
} catch (error) {
console.error(error);
res.status(error.status || 500).end(error.message);
}
}
import auth0 from '../../lib/auth0';
export default async function me(req, res) {
try {
await auth0().handleProfile(req, res);
} catch (error) {
console.error(error);
res.status(error.status || 500).end(error.message);
}
}
callback.js
は、ログイン時のcallbackにあたります。
上の設定時に、Auth0で、
- Allowed Callback URLs: http://localhost:3000/api/callback
としたのは、このためです。
/api/login
を経て、Auth0の認証画面から戻ってきた際、callbackにはクエリストリングとしてsession情報(やstate。今回はsessionしかありません)が渡されてきます。
handleCallback
は、このクエリストリングの情報を取得し、検証後に暗号化されたsession cookie
を保存する役割を果たしています。
Handling User State
componentsを作り始める前に、もうひと手間!
ユーザーのログイン状態を取り回すuser.js
をlib
に作っておきます。
個人的には、contextsやhocsに切り分けて書かれているほうが読みやすいような気がしたんですが、それはまた別の機会に挑戦してみます。
touch lib/user.js
import React from 'react';
import fetch from 'isomorphic-unfetch';
// グローバルにユーザーを保存することで、ページ遷移時に再度APIを呼んで読み込むことを回避。
let userState;
const User = React.createContext({ user: null, loading: false });
export const fetchUser = async () => {
if (userState !== undefined) {
return userState;
}
// 先ほど作った'api/me'を呼んで、ログインしているユーザーの情報を取得。
const res = await fetch('/api/me');
userState = res.ok ? await res.json() : null;
return userState;
};
export const UserProvider = ({ value, children }) => {
const { user } = value;
// SSR時にユーザーがfetchされていれば、userStateに追加。これにより、再度fetchする必要がなくなる。
React.useEffect(() => {
if (!userState && user) {
userState = user;
}
}, []);
return <User.Provider value={value}>{children}</User.Provider>;
};
export const useUser = () => React.useContext(User);
export const useFetchUser = () => {
const [data, setUser] = React.useState({
user: userState || null,
loading: userState === undefined
});
React.useEffect(() => {
if (userState !== undefined) {
return;
}
let isMounted = true;
fetchUser().then((user) => {
// componentがまだマウントされているときだけユーザーをセット。
if (isMounted) {
setUser({ user, loading: false });
}
});
return () => {
isMounted = false;
};
}, [userState]);
return data;
};
Creating Components
いよいよComponentの準備です。
ここでは、ヘッダーにログイン/ログアウトのボタンがある、一般的なレイアウトのページを作っていきます。
mkdir components
touch components/{header.jsx,layout.jsx}
import React from 'react';
import Link from 'next/link';
import { useUser } from '../lib/user'; //先ほどのuserからユーザーの状態をもらってくる。
const Header = () => {
const { user, loading } = useUser();
return (
<header>
<nav>
<ul>
<li>
<Link href="/">
<a>Home</a>
</Link>
</li>
{!loading &&
(user ? (
<>
<li>
<Link href="/profile">
<a>Profile</a>
</Link>
</li>{' '}
<li>
<a href="/api/logout">Logout</a>
</li>
</>
) : (
<>
<li>
<a href="/api/login">Login</a>
</li>
</>
))}
</ul>
</nav>
<style jsx>{`
header {
padding: 0.2rem;
color: #fff;
background-color: #333;
}
nav {
max-width: 42rem;
margin: 1.5rem auto;
}
ul {
display: flex;
list-style: none;
margin-left: 0;
padding-left: 0;
}
li {
margin-right: 1rem;
}
li:nth-child(1) {
margin-right: auto;
}
a {
color: #fff;
text-decoration: none;
}
button {
font-size: 1rem;
color: #fff;
cursor: pointer;
border: none;
background: none;
}
`}</style>
</header>
);
};
export default Header;
些細な点ですが、<style jsx>
で:nth-child(1)
という書き方をしているところがあります。
これは、公式ではページのバリエーションがもう少し多かった(本当は3だった)ためなので、:first-child
でもよいと思います。
import React from 'react';
import Head from 'next/head';
import Header from './header';
import { UserProvider } from '../lib/user';
const Layout = ({ user, loading = false, children }) => (
<UserProvider value={{ user, loading }}>
<Head>
<title>Next.js with Auth0</title>
</Head>
<Header />
<main>
<div className="container">{children}</div>
</main>
<style jsx>{`
.container {
max-width: 42rem;
margin: 1.5rem auto;
}
`}</style>
<style jsx global>{`
body {
margin: 0;
color: #333;
font-family: -apple-system, 'Segoe UI';
}
`}</style>
</UserProvider>
);
export default Layout;
Creating Pages
いよいよpages
を作っていきます。
touch pages/{index.jsx,profile.jsx}
import React from 'react';
import Layout from '../components/layout';
import { useFetchUser } from '../lib/user';
export default function Home() {
const { user, loading } = useFetchUser();
return (
<Layout user={user} loading={loading}>
<h1>Next.js and Auth0 Example</h1>
{loading && <p>Loading login info...</p>}
{!loading && !user && (
<>
<h4>Try it!</h4>
<p>
To test the login click in <i>Login</i>
</p>
</>
)}
{user && (
<>
<h4>Welcome!</h4>
<p>You successfully logged in!</p>
</>
)}
</Layout>
);
}
import React from 'react';
import Layout from '../components/layout';
import { useFetchUser } from '../lib/user';
export default function Profile() {
const { user, loading } = useFetchUser();
return (
<Layout user={user} loading={loading}>
<h1>Profile</h1>
{loading && <p>Loading profile...</p>}
{!loading && user && (
<>
<p>Profile:</p>
<pre>{JSON.stringify(user, null, 2)}</pre>
</>
)}
</Layout>
);
}
Test run!
まずはローカルでテストです。npm run dev
→http://localhost:3000
を確認してみます。
こんな画面が出てきます。Login
をclickしてみます。
Auth0が提供しているログインのウィジェットlock
が表示されます。
lock
もいろいろカスタマイズができて便利なのですが、今回の記事では触れません。
ログインを進めてみます。
狙い通り、メッセージが切り替わり、header
のメニューがProfile
とLogout
に切り替わりました。
ここで試しにcookie
をチェックしてみると、
a0:session
という名前で、セッションが保存されています。
また、指定通りSame-Site
はLax
、さらに標準でHttp-Only
になっていることがわかります。
これは前述したように、login後のcallbackで/api/callback
に帰ってきた際に、handleCallback
によってクエリストリングから保存しなおされたものです。
今回の記事では触れませんが、APIの保護に利用するauth token
などを取り回す場合は、同様にhandleCallback
がcookieに置き直してくれる情報を利用していきます。
では、お楽しみのProfile
ページを見てみましょう。
ここではGoogleを利用してログインしたので、OIDCで取れてくる情報がユーザー情報として表示されています。
sub
はユーザーのユニークなidにあたるものですが、Auth0の場合は{connection name}|{random id}
という形式になっています。
connection
とはユーザープール名のようなものですが、socail loginの場合は上記のようにgoogle-oauth2
などとid providerの種類が入ってきます。
また、ここでは、email
が含まれていないことに気づかれた方もいらっしゃるでしょう。
利用場面によっては、当然、「ユーザーのメールアドレスがほしい」ということもあると思います。
その場合は、.env
に記述したscope
の部分にemail
を追加し、openid profile email
とすると、メールアドレスが取れるようになります。
Deploy!
さて、最後にdeployの方法です。これはとんでもなく簡単です(注:まだやらないでください)。
npx serverless
終了! と言いたいところですが、上記したように、このままdeployしてもAuth0のSettingが済んでいません。
Auth0のコンソールを開き、上のAuth0の設定についてのセクションで、http://localhost:3000
やhttp://localhost:3000/api/callback
としていた部分に、serverless.yml
で指定したドメインについても追記する必要があります。
あらためて画像を貼ると、console
-->Applications
-->Settings
-->Application URLs
のセクションです。
また「テストの段階では削除しておいてください」と注記しておいた.env
にも、修正が必要です。
REDIRECT_URI
とPOST_LOGOUT_REDIRECT_URI
に、それぞれdeploy後の正しいURLを記述する必要があります。
REDIRECT_URI
のほうが、https://your.domain.com/api/callback
の形になります。
ここまで確認できたら、上述のnpx serverless
を実行してみてください。
deployの速度が早いことも体感できると思います。
この高速deployを可能にしている大きな理由のひとつが、Serverless Next.jsがCloudFormationを利用していないことです。
Behind the Curtain
今回、nextjs-auth0
を使ってみようと思ったのは、次のブログを読んだからでした。
https://auth0.com/blog/ultimate-guide-nextjs-authentication-auth0/
このブログでは、Next.jsでAuthenticationを実装する代表的なシナリオについて、それぞれの具体的な方法や長所・短所がまとめられています。
中でも興味をひかれたのが、 "Next.js Serverless Deployment Model" というセクションでした。
ここに、上でたびたび触れた、callback
での挙動に関連した説明がありますので、はしょりながらですが、ざっと訳してみようと思います。
......Next.jsがその輝きを見せるのは、すべてのページやAPI Routeが、それぞれZEIT NowやAWS Lambdaのようなserverless functionとして実装される、serverless deployment modelのもとで利用される場面だ。
このモデルでは、(Express.jsのような)本格的なweb frameworkは存在しない。その代わり、ランタイムは( (req, res)=>{} という形で)リクエストとレスポンスのオブジェクトをやりとりする関数を実行することになる。そして、このことが我々がExpress.jsのような伝統的なweb frameworkや、Passport.jsのようにユーザーの認証を取り回したり、express-sessionsのようにsessionを作ったりする、できあいのパッケージを利用できない大きな理由になっている。
(中略)
......
nextjs-auth0
を利用すると、ユーザーはAuthorization Code Grantを利用してサインインすることになる。ユーザーはまず、必要なすべての認証認可ロジック(サインアップ、サインイン、MFA、<social loginなどの>許可など)を取り回すAuth0にリダイレクトされ、そののち、(サービス側の)アプリケーションにクエリストリングにAuthorizationCodeを含んだ状態でリダイレクトされて帰ってくる。
サーバサイド(というより、serverless function)は、このコードを
id_token
、またオプションとしてaccess_token
やrefresh_token
と交換する。id_token
が検証されたのち、セッションが作られ、暗号化されたcookieとして保存される。ページが(サーバサイドで)レンダリングされるか、API Routeが呼ばれるたびに、session cookieがserverless functionsに渡されることで、serverless functionsはセッションや関連するユーザー情報にアクセスすることができるようになる。
実のところ、今回、実験してみた範囲は、クライアントサイドのみでのuser
の取り回しでした。
なので、たとえばProfile
ページのURLをログインしていない状態で直に叩くと、次のような画面になります。
もちろん、不用意にuser
の情報が露出するといったことはないわけですが、実際のサービスを構築する場面を想定すると、ユーザー情報が抜けた「枠」だけのページであっても、非ログイン状態のユーザーがアクセスできるのは、いささか不都合です。
しかし、上の翻訳にあるように、nextjs-auth0
を利用する方法なら、サーバサイドでユーザー情報を利用することもできるわけです。
次回は、サーバサイドでuser
を見ることで、非ログインユーザーによるURLへの直アクセスでログインを求める仕掛けを作る方法を書いてみたいと思います。