next-auth 使ってみる
Getting Started
とりあえず Docs の Getting Started を進めてく
The easiest way to get started is to clone the example app and follow the instructions in README.md.
とのことなので、こちら の repo を手元で動かしいてみる
example app の構成はこんな感じ。
pages
├── _app.js
├── _middleware.js
├── api
│ ├── auth
│ │ └── [...nextauth].js
│ └── examples
│ ├── jwt.js
│ ├── protected.js
│ └── session.js
├── api-example.js
├── client.js
├── index.js
├── middleware-protected.js
├── policy.js
├── protected.js
├── server.js
└── styles.css
pages/api/auth/[...nextauth].js が認証 API の核っぽい
example app のデフォのものを貼り付けとく
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import FacebookProvider from "next-auth/providers/facebook"
import GithubProvider from "next-auth/providers/github"
import TwitterProvider from "next-auth/providers/twitter"
import Auth0Provider from "next-auth/providers/auth0"
// import AppleProvider from "next-auth/providers/apple"
// import EmailProvider from "next-auth/providers/email"
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export default NextAuth({
// https://next-auth.js.org/configuration/providers
providers: [
/* EmailProvider({
server: process.env.EMAIL_SERVER,
from: process.env.EMAIL_FROM,
}),
// Temporarily removing the Apple provider from the demo site as the
// callback URL for it needs updating due to Vercel changing domains
Providers.Apple({
clientId: process.env.APPLE_ID,
clientSecret: {
appleId: process.env.APPLE_ID,
teamId: process.env.APPLE_TEAM_ID,
privateKey: process.env.APPLE_PRIVATE_KEY,
keyId: process.env.APPLE_KEY_ID,
},
}),
*/
FacebookProvider({
clientId: process.env.FACEBOOK_ID,
clientSecret: process.env.FACEBOOK_SECRET,
}),
GithubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
// https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps
scope: "read:user",
}),
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
TwitterProvider({
clientId: process.env.TWITTER_ID,
clientSecret: process.env.TWITTER_SECRET,
}),
Auth0Provider({
clientId: process.env.AUTH0_ID,
clientSecret: process.env.AUTH0_SECRET,
issuer: process.env.AUTH0_ISSUER,
}),
],
// The secret should be set to a reasonably long random string.
// It is used to sign cookies and to sign and encrypt JSON Web Tokens, unless
// a separate secret is defined explicitly for encrypting the JWT.
secret: process.env.SECRET,
session: {
// Use JSON Web Tokens for session instead of database sessions.
// This option can be used with or without a database for users/accounts.
// Note: `strategy` should be set to 'jwt' if no database is used.
strategy: "jwt",
// Seconds - How long until an idle session expires and is no longer valid.
// maxAge: 30 * 24 * 60 * 60, // 30 days
// Seconds - Throttle how frequently to write to database to extend a session.
// Use it to limit write operations. Set to 0 to always update the database.
// Note: This option is ignored if using JSON Web Tokens
// updateAge: 24 * 60 * 60, // 24 hours
},
// JSON Web tokens are only used for sessions if the `jwt: true` session
// option is set - or by default if no database is specified.
// https://next-auth.js.org/configuration/options#jwt
jwt: {
// You can define your own encode/decode functions for signing and encryption
// if you want to override the default behaviour.
// encode: async ({ secret, token, maxAge }) => {},
// decode: async ({ secret, token, maxAge }) => {},
},
// You can define custom pages to override the built-in ones. These will be regular Next.js pages
// so ensure that they are placed outside of the '/api' folder, e.g. signIn: '/auth/mycustom-signin'
// The routes shown here are the default URLs that will be used when a custom
// pages is not specified for that route.
// https://next-auth.js.org/configuration/pages
pages: {
// signIn: '/auth/signin', // Displays signin buttons
// signOut: '/auth/signout', // Displays form with sign out button
// error: '/auth/error', // Error code passed in query string as ?error=
// verifyRequest: '/auth/verify-request', // Used for check email page
// newUser: null // If set, new users will be directed here on first sign in
},
// Callbacks are asynchronous functions you can use to control what happens
// when an action is performed.
// https://next-auth.js.org/configuration/callbacks
callbacks: {
// async signIn({ user, account, profile, email, credentials }) { return true },
// async redirect({ url, baseUrl }) { return baseUrl },
// async session({ session, token, user }) { return session },
// async jwt({ token, user, account, profile, isNewUser }) { return token }
},
// Events are useful for logging
// https://next-auth.js.org/configuration/events
events: {},
// You can set the theme to 'light', 'dark' or use 'auto' to default to the
// whatever prefers-color-scheme is set to in the browser. Default is 'auto'
theme: {
colorScheme: "light",
},
// Enable debug messages in the console if you are having problems
debug: false,
})
evn.local に clientId やら secretKey などの認証に必要な情報を設定してあげれば、以下 provider ですぐ認証機能が試せる。めちゃ楽。
- GitHub
- Auth0
Adapters
An Adapter in NextAuth.js connects your application to whatever database or backend system you want to use to store data for users, their accounts, sessions, etc. Adapters are optional, unless you need to persist user information in your own database, or you want to implement certain flows. The Email Provider requires an adapter to be able to save Verification Tokens.
adaptor を使えば user に関するデータをデータベースに保存できるのか
adaptorの種類
- prisma
- fauna
- dynamodb
- firebase
- pouchdb
- mongodb
- neo4j
- typeorm-legacy
- sequelize
- dgraph
Client API
useSession
data: This can be three values: Session / undefined / null.
when the session hasn't been fetched yet, data will undefined
in case it failed to retrieve the session, data will be null
in case of success, data will be Session.
undefined と null 使い分けてるのおもしろいな
SignIn Page について
example app の /api/auth/signin にアクセスすると signin page が表示される。こんなの↓
これはデフォで表示されるやつっぽい...? UI はどうやって修正するんだろ

ここに書いてあった
// You can define custom pages to override the built-in ones. These will be regular Next.js pages
// so ensure that they are placed outside of the '/api' folder, e.g. signIn: '/auth/mycustom-signin'
// The routes shown here are the default URLs that will be used when a custom
// pages is not specified for that route.
// https://next-auth.js.org/configuration/pages
pages: {
// signIn: '/auth/signin', // Displays signin buttons
// signOut: '/auth/signout', // Displays form with sign out button
// error: '/auth/error', // Error code passed in query string as ?error=
// verifyRequest: '/auth/verify-request', // Used for check email page
// newUser: null // If set, new users will be directed here on first sign in
},
詳しくはこちらか
NextAuth.js automatically creates simple, unbranded authentication pages for handling Sign in, Sign out, Email Verification and displaying error messages.
The options displayed on the sign up page are automatically generated based on the providers specified in the options passed to NextAuth.js.
UI は何も用意しなくても、NextAuth が用意したものを表示してくれるみたい。しかも、Provider で指定したものに応じて、適したボタンを含む SignIn Page を表示してくれる。
ためしに、FacebookProvider をコメントアウトしたらちゃんと "Sign in with Facebook"のボタンが消えた。素晴らしい。
/api/auth/providers にリクエスト投げると、provider の情報が json でとれる。
example app で /api/auth/providers にアクセスするとこれが返ってくる↓
facebook: {
id: 'facebook',
name: 'Facebook',
type: 'oauth',
signinUrl: 'http://localhost:3000/api/auth/signin/facebook',
callbackUrl: 'http://localhost:3000/api/auth/callback/facebook',
},
github: {
id: 'github',
name: 'GitHub',
type: 'oauth',
signinUrl: 'http://localhost:3000/api/auth/signin/github',
callbackUrl: 'http://localhost:3000/api/auth/callback/github',
},
google: {
id: 'google',
name: 'Google',
type: 'oauth',
signinUrl: 'http://localhost:3000/api/auth/signin/google',
callbackUrl: 'http://localhost:3000/api/auth/callback/google',
},
twitter: {
id: 'twitter',
name: 'Twitter',
type: 'oauth',
signinUrl: 'http://localhost:3000/api/auth/signin/twitter',
callbackUrl: 'http://localhost:3000/api/auth/callback/twitter',
},
auth0: {
id: 'auth0',
name: 'Auth0',
type: 'oauth',
signinUrl: 'http://localhost:3000/api/auth/signin/auth0',
callbackUrl: 'http://localhost:3000/api/auth/callback/auth0',
},
};
デフォの SignIn Page をカスタマイズしたい場合は、page component 作成して、その path を NextAuth options.pages.singin に指定すればOK。
pages/auth/signin.jsを SignIn Page として利用したい場合はこんな感じ↓
この状態で /api/auth/signin にアクセスすると、/auth/signin に redirect されて、MySignInPage component が表示される。
import Layout from '../../components/layout';
export default function MySignInPage() {
return (
<Layout>
<h1>My SignIn Page!!!</h1>
</Layout>
);
}
pages: {
signIn: '/auth/signin',
},
自前の SignIn Page を使用する場合、signIn(providerId) を呼び出してあげる必要がある。
e.g) signIn('google') : google サインインを開始
NextAuth options で指定した Provider の情報は、getProvider() で取得できる (server-side, client-side どちらでも使用可能)。以下の sample は Provider ごとの signIn button を作成している。
(memo) getToken() は /api/auth/providers にリクエスト投げてる
import { getProviders, signIn } from 'next-auth/react';
import useSWR from 'swr';
import Layout from '../../components/layout';
export default function Page() {
const { data: providers, error } = useSWR('/api/auth/providers', () =>
getProviders()
);
if (error) return <p>Oops something went wrong...</p>;
if (!providers) return <p>Loading...</p>;
return (
<Layout>
<h1>My SignIn Page!!!</h1>
{Object.values(providers).map((provider) => {
return (
<div key={provider.name}>
<button onClick={() => signIn(provider.id)}>
SignIn with {provider.name}
</button>
</div>
);
})}
</Layout>
);
}
NexAuth options.theme でも多少 UI を変更できる。
theme: {
colorScheme: "auto", // "auto" | "dark" | "light"
brandColor: "", // Hex color code
logo: "" // Absolute URL to image
}
colorSchema, brandColor, logo しか変えられない。
signIn でエラー起きると、query params にエラーコードがつくみたい。
e.g) &error=OAuthSignin : clientId, clientSecret を設定しないで facebook の signIn を試みた後
これをいい感じに扱えるような util 提供してくれてないかな....
Typescript
next-auth + typescript な sample repo