Compare commits

...

21 Commits
v2.0 ... v2.1.0

Author SHA1 Message Date
Iain Collins
f899d7bb04 Update version to 2.1.0 2020-06-24 01:57:28 +01:00
Iain Collins
e36646ce7f Update docs formatting 2020-06-24 01:53:49 +01:00
Iain Collins
f3d36a74c9 Update provider documentation 2020-06-24 01:53:49 +01:00
Iain Collins
4e11c9c36e Fix linter errors 2020-06-24 01:26:07 +01:00
Iain Collins
0a7ac36584 Update client documentation 2020-06-24 01:26:07 +01:00
Iain Collins
fc4850f354 Update documentation for client and options 2020-06-24 01:26:07 +01:00
Iain Collins
6e9a8d2074 Update beta version 2020-06-24 01:26:07 +01:00
Iain Collins
c712d7da07 Remove base URL cookie; no longer needed 2020-06-24 01:26:07 +01:00
Iain Collins
5183181d1c Refactor client to allow provider to be passed options 2020-06-24 01:26:07 +01:00
Iain Collins
b024f89ba8 Update client max age documentation 2020-06-24 01:26:07 +01:00
Iain Collins
fbbe516b9a Refactor client to take configuraiton from _app.js 2020-06-24 01:26:07 +01:00
Iain Collins
d48a3fd948 Rename internal debug env var for consistancy
This is a naughty global used server side to more easily facilitate debugging.
2020-06-24 01:26:07 +01:00
ndo@$(hostname)
86f0c53bd3 add: npm publish workflow 2020-06-24 01:19:51 +01:00
Onur
7f6cc2048b Minor typo fix 2020-06-24 00:00:09 +01:00
Lori Karikari
b2829f6384 added missing comma to homepage example 2020-06-23 18:33:59 +02:00
Iain Collins
67c5041860 Remove console.log from auth0 provider 2020-06-23 13:00:25 +01:00
Lori Karikari
33df9e3132 updated Cognito (#307) 2020-06-23 11:40:18 +02:00
Lori Karikari
602bc28a45 Add new OAuth providers (#221) 2020-06-23 11:31:18 +02:00
jose-donato
5a7a494701 typo 2020-06-23 00:34:44 +01:00
Iain Collins
9fa82cedbd Fix Auth0 provider
Resolves #301
2020-06-23 00:13:55 +01:00
Iain Collins
b0408284b8 Tweak homepage CSS 2020-06-21 17:30:43 +01:00
44 changed files with 363 additions and 281 deletions

36
.github/workflows/npm-publish.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
# Publishes module to registry when a new release is created.
#
# The following secrets need to be configured for this workflow:
#
# * NPM_TOKEN - Auth token from npmjs.com
name: Publish to NPM
on:
release:
types: [created]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
- run: npm ci
- run: npm test
publish-npm:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
registry-url: https://registry.npmjs.org/
- run: npm ci
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "next-auth",
"version": "2.0.0",
"version": "2.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "next-auth",
"version": "2.0.0",
"version": "2.1.0",
"description": "An authentication library for Next.js",
"repository": "https://github.com/iaincollins/next-auth.git",
"author": "Iain Collins <me@iaincollins.com>",

View File

@@ -15,4 +15,4 @@ const css = fs.readFileSync(pathToCss, 'utf8')
const cssWithEscapedQuotes = css.replace(/"/gm, '\\"')
const js = `module.exports = function() { return "${cssWithEscapedQuotes}" }`
fs.writeFileSync(pathToCssJs, js)
fs.writeFileSync(pathToCssJs, js)

View File

@@ -3,41 +3,47 @@
import { useState, useEffect, useContext, createContext, createElement } from 'react'
import logger from '../lib/logger'
// Note: In calls to fetch() from universal methods, all cookies are passed
// through from the browser, when the server makes the HTTP request, so that
// it can authenticate as the browser.
const __NEXTAUTH = {
site: '',
basePath: '/api/auth',
clientMaxAge: 0 // e.g. 0 == disabled, 60 == 60 seconds
}
// These can be overridden with NEXTAUTH_ env vars in next.config.js
// e.g. process.env.NEXTAUTH_SITE
const NEXTAUTH_DEFAULT_BASE_URL_COOKIE_NAME = 'next-auth.base-url'
const NEXTAUTH_DEFAULT_SITE = ''
const NEXTAUTH_DEFAULT_BASE_PATH = '/api/auth'
const NEXTAUTH_DEFAULT_CLIENT_MAXAGE = 0 // e.g. 0 == disabled, 60 == 60 seconds
let __NEXTAUTH_EVENT_LISTENER_ADDED = false
let NEXTAUTH_EVENT_LISTENER_ADDED = false
// Method to set options. The documented way is to use the provider, but this
// method is being left in as an alternative, that will be helpful if/when we
// expose a vanilla JavaScript version that doesn't depend on React.
const setOptions = ({
site,
basePath,
clientMaxAge
} = {}) => {
if (site) { __NEXTAUTH.site = site }
if (basePath) { __NEXTAUTH.basePath = basePath }
if (clientMaxAge) { __NEXTAUTH.clientMaxAge = clientMaxAge }
}
// Universal method (client + server)
const getSession = async ({ req } = {}) => {
const baseUrl = _baseUrl({ req })
const baseUrl = _baseUrl()
const options = req ? { headers: { cookie: req.headers.cookie } } : {}
const session = await _fetchData(`${baseUrl}/session`, options)
_sendMessage({ event: 'session', data: { triggeredBy: 'getSession' } })
_sendMessage({ event: 'session', data: { trigger: 'getSession' } })
return session
}
// Universal method (client + server)
const getProviders = async ({ req } = {}) => {
const baseUrl = _baseUrl({ req })
const options = req ? { headers: { cookie: req.headers.cookie } } : {}
return _fetchData(`${baseUrl}/providers`, options)
const getProviders = async () => {
const baseUrl = _baseUrl()
return _fetchData(`${baseUrl}/providers`)
}
// Universal method (client + server)
const getCsrfToken = async ({ req } = {}) => {
const baseUrl = _baseUrl({ req })
const options = req ? { headers: { cookie: req.headers.cookie } } : {}
const data = await _fetchData(`${baseUrl}/csrf`, options)
return data.csrfToken
const getCsrfToken = async () => {
const baseUrl = _baseUrl()
const data = await _fetchData(`${baseUrl}/csrf`)
return data && data.csrfToken ? data.csrfToken : null
}
// Context to store session data globally
@@ -57,8 +63,7 @@ const useSession = (session) => {
// Internal hook for getting session from the api.
const useSessionData = (session) => {
const clientMaxAge = (process.env.NEXTAUTH_CLIENT_MAXAGE || NEXTAUTH_DEFAULT_CLIENT_MAXAGE) * 1000
const clientMaxAge = __NEXTAUTH.clientMaxAge * 1000
const [data, setData] = useState(session)
const [loading, setLoading] = useState(true)
const _getSession = async (sendEvent = true) => {
@@ -68,17 +73,17 @@ const useSessionData = (session) => {
// Send event to trigger other tabs to update (unless sendEvent is false)
if (sendEvent) {
_sendMessage({ event: 'session', data: { triggeredBy: 'useSessionData' } })
_sendMessage({ event: 'session', data: { trigger: 'useSessionData' } })
}
if (typeof window !== 'undefined' && NEXTAUTH_EVENT_LISTENER_ADDED === false) {
NEXTAUTH_EVENT_LISTENER_ADDED = true
if (typeof window !== 'undefined' && __NEXTAUTH_EVENT_LISTENER_ADDED === false) {
__NEXTAUTH_EVENT_LISTENER_ADDED = true
window.addEventListener('storage', async (event) => {
if (event.key === 'nextauth.message') {
const message = JSON.parse(event.newValue)
if (message.event && message.event === 'session' && message.data) {
// Fetch new session data but tell it not to fire an event to
// avoid an infinate loop.
// avoid an infinite loop.
//
// Note: We could pass session data through and do something like
// `setData(message.data)` but that causes problems depending on
@@ -159,18 +164,18 @@ const signout = async (args) => {
}
const res = await fetch(`${baseUrl}/signout`, options)
_sendMessage({ event: 'session', data: { triggeredBy: 'signout' } })
_sendMessage({ event: 'session', data: { trigger: 'signout' } })
window.location = res.url ? res.url : callbackUrl
}
// Provider to wrap the app in to make session data available globally
const Provider = ({ children, session }) => {
const value = useSession(session)
return createElement(SessionContext.Provider, { value }, children)
const Provider = ({ children, session, options }) => {
setOptions(options)
return createElement(SessionContext.Provider, { value: useSession(session) }, children)
}
const _fetchData = async (url, options) => {
const _fetchData = async (url, options = {}) => {
try {
const res = await fetch(url, options)
const data = await res.json()
@@ -181,44 +186,7 @@ const _fetchData = async (url, options) => {
}
}
const _baseUrl = ({ req } = {}) => {
if (req) {
// Server Side
// If we have a 'req' object are running sever side, so we should grab the
// base URL from cookie that is set by the API route - which is how config
// is shared automatically between the API route and the client.
const cookies = req ? _parseCookies(req.headers.cookie) : null
const baseUrlCookieName = process.env.NEXTAUTH_BASE_URL_COOKIE_NAME || NEXTAUTH_DEFAULT_BASE_URL_COOKIE_NAME
const cookieValue = cookies[`__Secure-${baseUrlCookieName}`] || cookies[baseUrlCookieName]
const [baseUrl] = cookieValue ? cookieValue.split('|') : [null]
return baseUrl
} else {
// Client Side
// Note: 'site' is empty by default; URL is normally relative.
const site = process.env.NEXTAUTH_SITE || NEXTAUTH_DEFAULT_SITE
const basePath = process.env.NEXTAUTH_BASE_PATH || NEXTAUTH_DEFAULT_BASE_PATH
return `${site}${basePath}`
}
}
// Adapted from https://github.com/felixfong227/simple-cookie-parser/blob/master/index.js
const _parseCookies = (string) => {
if (!string) { return {} }
try {
const object = {}
const a = string.split(';')
for (let i = 0; i < a.length; i++) {
const b = a[i].split('=')
if (b[0].length > 1 && b[1]) {
object[b[0].trim()] = decodeURIComponent(b[1])
}
}
return object
} catch (error) {
logger.error('CLIENT_COOKIE_PARSE_ERROR', error)
return {}
}
}
const _baseUrl = () => `${__NEXTAUTH.site}${__NEXTAUTH.basePath}`
const _encodedForm = (formData) => {
return Object.keys(formData).map((key) => {
@@ -233,6 +201,10 @@ const _sendMessage = (message) => {
}
export default {
// Call config() from _app.js to set options globally in the app.
// You need to set at least the site name to use server side calls.
options: setOptions,
setOptions,
// Some methods are exported with more than one name. This provides
// flexibility over how they can be invoked and compatibility with earlier
// releases (going back to v1 and earlier v2 beta releases).

View File

@@ -7,4 +7,4 @@ import path from 'path'
const pathToCss = path.join(__dirname, '/index.css')
const css = fs.readFileSync(pathToCss, 'utf8')
export default () => css
export default () => css

View File

@@ -11,7 +11,7 @@ const logger = {
}
},
debug: (debugCode, ...text) => {
if (process && process.env && process.env._NEXT_AUTH_DEBUG) {
if (process && process.env && process.env._NEXTAUTH_DEBUG) {
console.log(
`[next-auth][debug][${debugCode}]`,
text

View File

@@ -4,11 +4,11 @@ export default (options) => {
name: 'Auth0',
type: 'oauth',
version: '2.0',
params: { grant_type: 'authorization_code', response_type: 'code' },
params: { grant_type: 'authorization_code' },
scope: 'openid email profile',
accessTokenUrl: `https://${options.subdomain}.auth0/oauth/token`,
authorizationUrl: `https://${options.subdomain}.auth0.com/authorize?`,
profileUrl: `http://${options.subdomain}.auth0.com/userinfo`,
accessTokenUrl: `https://${options.domain}/oauth/token`,
authorizationUrl: `https://${options.domain}/authorize?response_type=code`,
profileUrl: `https://${options.domain}/userinfo`,
profile: (profile) => {
return {
id: profile.sub,

View File

@@ -0,0 +1,29 @@
export default (options) => {
const { region } = options
return {
id: 'battlenet',
name: 'Battle.net',
type: 'oauth',
version: '2.0',
scope: 'openid',
params: { grant_type: 'authorization_code' },
accessTokenUrl:
region === 'CN'
? 'https://www.battlenet.com.cn/oauth/token'
: `https://${region}.battle.net/oauth/token`,
authorizationUrl:
region === 'CN'
? 'https://www.battlenet.com.cn/oauth/authorize'
: `https://${region}.battle.net/oauth/authorize`,
profileUrl: 'https://us.battle.net/oauth/userinfo',
profile: (profile) => {
return {
id: profile.id,
name: profile.battletag,
email: null,
image: null
}
},
...options
}
}

23
src/providers/cognito.js Normal file
View File

@@ -0,0 +1,23 @@
export default (options) => {
const { domain } = options
return {
id: 'cognito',
name: 'Cognito',
type: 'oauth',
version: '2.0',
scope: 'openid profile email',
params: { grant_type: 'authorization_code' },
accessTokenUrl: `https://${domain}/oauth2/token`,
authorizationUrl: `https://${domain}/oauth2/authorize?response_type=code`,
profileUrl: `https://${domain}/oauth2/userInfo`,
profile: (profile) => {
return {
id: profile.sub,
name: profile.username,
email: profile.email,
image: null
}
},
...options
}
}

View File

@@ -2,9 +2,11 @@ import Auth0 from './auth0'
import Apple from './apple'
import Box from './box'
import Credentials from './credentials'
import BattleNet from './battlenet'
import Cognito from './cognito'
import Discord from './discord'
import Email from './email'
import Facebook from './facebook' // @TODO
import Facebook from './facebook'
import GitHub from './github'
import GitLab from './gitlab'
import Google from './google'
@@ -21,6 +23,8 @@ export default {
Apple,
Box,
Credentials,
BattleNet,
Cognito,
Discord,
Email,
Facebook,

View File

@@ -89,15 +89,6 @@ export default async (req, res, userSuppliedOptions) => {
secure: useSecureCookies
}
},
baseUrl: {
name: `${cookiePrefix}next-auth.base-url`,
options: {
httpOnly: true,
sameSite: 'lax',
path: '/',
secure: useSecureCookies
}
},
csrfToken: {
// Default to __Host- for CSRF token for additional protection if using useSecureCookies
// NB: The `__Host-` prefix is stricter than the `__Secure-` prefix.
@@ -180,24 +171,6 @@ export default async (req, res, userSuppliedOptions) => {
cookie.set(res, cookies.csrfToken.name, newCsrfTokenCookie, cookies.csrfToken.options)
}
// Set canonical site name + API route in a cookie to facilitate passing configuration
// to the NextAuth client. There are potential security considerations around this
// relating to trying to prevent attackers from exploiting this by setting this cookie
// on the client first if they can get control of a sub domain or exploit a XSS
// vulnerability, but this approach attempts to mitgate that by always verifying
// the cookie and updating it if fails the verification check.
let setUrlPrefixCookie = true
if (req.cookies[cookies.baseUrl.name]) {
const [baseUrlValue, baseUrlHash] = req.cookies[cookies.baseUrl.name].split('|')
// If the hash on the cookie is verified, then we must have set the cookie and don't need to update it
if (baseUrlValue === baseUrl && baseUrlHash === createHash('sha256').update(`${baseUrlValue}${secret}`).digest('hex')) { setUrlPrefixCookie = false }
}
// If the cookie is not set already (or if it is set, but failed verification) set header to update the cookie
if (setUrlPrefixCookie) {
const newUrlPrefixCookie = `${baseUrl}|${createHash('sha256').update(`${baseUrl}${secret}`).digest('hex')}`
cookie.set(res, cookies.baseUrl.name, newUrlPrefixCookie, cookies.baseUrl.options)
}
// User provided options are overriden by other options,
// except for the options with special handling above
const options = {
@@ -227,7 +200,7 @@ export default async (req, res, userSuppliedOptions) => {
}
// If debug enabled, set ENV VAR so that logger logs debug messages
if (options.debug === true) { process.env._NEXT_AUTH_DEBUG = true }
if (options.debug === true) { process.env._NEXTAUTH_DEBUG = true }
// Get / Set callback URL based on query param / cookie + validation
options.callbackUrl = await callbackUrlHandler(req, res, options)

View File

@@ -1,5 +1,3 @@
import fs from 'fs'
import path from 'path'
import signin from './signin'
import signout from './signout'
import verifyRequest from './verify-request'

View File

@@ -7,16 +7,16 @@ Callbacks are asynchronous functions you can use to control what happens when an
Callbacks are extremely powerful, especially in scenarios involving JSON Web Tokens as they allow you to implement access controls without a database and to integrate with external databases or APIs.
### Example
You can specify a handler for any of the callbacks below.
#### How to use the callback option
```js
```js title="pages/api/auth/[...nextauth.js]"
callbacks: {
signin: async (profile, account, metadata) => { },
redirect: async (url, baseUrl) => { },
session: async (session, token) => { },
jwt: async (token) => { }
jwt: async (token, oAuthProfile) => { }
}
```

View File

@@ -0,0 +1,23 @@
---
id: events
title: Events
---
Events are asynchronous functions that do not return a response, they are useful for audit logging.
### Example
You can specify a handler for any of these events below - e.g. for debugging or to create an audit log.
```js title="pages/api/auth/[...nextauth.js]"
events: {
signin: async (message) => { /* on successful sign in */ },
signout: async (message) => { /* on signout */ },
createUser: async (message) => { /* user created */ },
linkAccount: async (message) => { /* account linked to a user */ },
session: async (message) => { /* session is active */ },
error: async (message) => { /* error in authentication flow */ }
}
```
The content of the message object varies depending on the flow (e.g. OAuth or Email authentication flow, JWT or database sessions, etc), but typically contains a user object and/or contents of the JSON Web Token and other information relevent to the event.

View File

@@ -289,20 +289,16 @@ Advanced options are passed the same way as basic options, but may have complex
This option allows you to specify a different base path if you don't want to use `/api/auth` for some reason.
If you set this option you **must** also specify the same value in the `NEXTAUTH_BASE_PATH` environment variable in `next.config.js` so that the client knows how to contact the server:
If you set this option you **must** also configure it along with the `site` property in `pages/_app.js`
```js title="next.config.js"
module.exports = {
env: {
NEXTAUTH_BASE_PATH: '/api/my-custom-auth-route',
},
}
```js title="pages/_app.js"
import { config } from 'next-auth/client'
config({
site: process.env.SITE, // e.g. 'http://localhost:3000'
basePath: process.env.BASE_PATH // e.g. '/api/some-other-route-name'
})
```
This is required because the NextAuth.js API route is a separate codepath to the NextAuth.js Client.
As long as you also specify this option in an environment variable, the client will be able to pick up any subsequent configuration from the server, but if you do not set in both it the NextAuth.js Client will not work.
---
### adapter
@@ -379,15 +375,6 @@ cookies: {
secure: true
}
},
baseUrl: {
name: `__Secure-next-auth.base-url`,
options: {
httpOnly: true,
sameSite: 'lax',
path: '/',
secure: true
}
},
csrfToken: {
name: `__Host-next-auth.csrf-token`,
options: {
@@ -403,38 +390,3 @@ cookies: {
:::warning
Changing the cookie options may introduce security flaws into your application and may break NextAuth.js integration now or in a future update. Using this option is not recommended.
:::
---
### Client Max Age
* **Default value**: `0`
* **Required**: *No*
#### Description
By default the NextAuth.js client will use whatever cached session object it has and will not not re-check the current session if using the `useSession()` hook.
You can change this behaviour and force it to periodically sync the session state by setting a `NEXTAUTH_CLIENT_MAXAGE` environment variable.
```js title="next.config.js"
module.exports = {
env: {
NEXTAUTH_CLIENT_MAXAGE: 60, // Will re-check session every 60 seconds
},
}
```
If set to `0` (the default) sessions are not re-checked automatically, only when a new window or tab is opened or when `getSession()` is called.
If set to any other value, specifies how many seconds the window or tab should poll the server to update the session data.
When a session is checked this way (or using `getSession()`) it is active and extends the life of the current session.
It can be useful to use this option to prevent sessions from timing out if your application has a short session expiry time.
This option usually has cost implications as checking session status triggers a call to a server side route and/or a database.
:::note
In NextAuth.js session state is automatically synchronized across all open windows and tabs in the same browser. If you have session expiry times of 30 days or more (the default) you probably don't need to use this option, or can set it to a high value (e.g. every 24 hours).
:::

View File

@@ -7,11 +7,11 @@ NextAuth.js automatically creates simple, unbranded authentication pages for han
The options displayed on the sign up page are automatically generated based on the providers specified in the options passed to NextAuth.js.
## Using custom pages
### Example
To add a custom login page, for example. You can us the `pages` option:
```javascript title="/pages/api/auth/[...nextauth].js"
```javascript title="pages/api/auth/[...nextauth].js"
...
pages: {
signin: '/auth/signin',
@@ -29,7 +29,7 @@ To add a custom login page, for example. You can us the `pages` option:
In order to get the available authentication providers and the URLs to use for them, you can make a request to the API endpoint `/api/auth/providers`:
```jsx title="/pages/auth/signin"
```jsx title="pages/auth/signin"
import React from 'react'
import { providers, signin } from 'next-auth/client'
@@ -70,7 +70,7 @@ This is easier of if you use the build in `signin()` function, as it sets the CS
To create a sign in page that works on clients with and without client side JavaScript, you can use both the **signin()** method and the **csrfToken()** method
:::
```jsx title="/pages/auth/email-signin"
```jsx title="pages/auth/email-signin"
import React from 'react'
import { csrfToken, signin } from 'next-auth/client'

View File

@@ -23,7 +23,9 @@ NextAuth.js is designed to work with any OAuth service, it supports OAuth 1.0, 1
* [Apple](/providers/apple)
* [Auth0](/providers/auth0)
* [Battle.net](/providers/battlenet)
* [Box](/providers/box)
* [Amazon Cognito](/providers/cognito)
* [Discord](/providers/discord)
* [Facebook](/providers/facebook)
* [GitHub](/providers/github)

View File

@@ -8,7 +8,22 @@ The NextAuth.js client library makes it easy to interact with sessions from Reac
Some of the methods can be called both client side and server side.
:::note
When using any of the client API methods server side, [context](https://nextjs.org/docs/api-reference/data-fetching/getInitialProps#context-object) must be passed as an argument. The documentation for **getSession()** has an example.
To use client methods server side in `getServerSideProp()` or `getInitialProps()` you should add the NextAuth.js `<Provider>` in `pages/apps.js`
```jsx title="pages/_app.js"
import { Provider } from 'next-auth/client'
export default ({ Component, pageProps }) => {
const { session } = pageProps
return (
<Provider options={{ site: process.env.SITE }} session={session} >
<Component {...pageProps} />
</Provider>
)
}
```
Specify the same site name as used in the route. [Documentation for `<Provider>`](/getting-started/client#provider)
:::
## useSession()
@@ -64,9 +79,9 @@ You can call `getSession()` inside a function to check if a user is signed in, o
Note that because it exposed to the client it does not contain sensitive information such as the Session Token or OAuth service related tokens. It includes enough information (e.g name, email) to display information on a page about the user who is signed in, and an Access Token that can be used to identify the session without exposing the Session Token itself.
:::
Because it is a Universal method, you can use `getSession()` in both client and server side functions, such as `getInitialProps()` in Next.js:
Because it is a Universal method, you can use `getSession()` in both client and server side functions.
```jsx title="/pages/index.js"
```jsx title="pages/index.js"
import { getSession } from 'next-auth/client'
const Page = ({ session }) => (<p>
@@ -89,36 +104,8 @@ Page.getInitialProps = async (context) => {
export default Page
```
#### Using getSession() in API routes
You can also get the session object in Next.js API routes:
```js
import { getSession } from 'next-auth/client'
export default (req, res) => {
const session = await getSession({ req })
if (session) {
// Signed in
const { accessToken } = session.user
// Do something with accessToken (e.g. look up user in DB)
res.statusCode = 200
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify({ /* data */ }))
} else {
// Not signed in
res.status(302).setHeader('Location', pages.newUser)
res.end()
}
}
```
:::note
When calling `getSession()` server side, you must pass the request object - e.g. `getSession({req})` - or you can the pass entire `context` object as it contains the `req` object.
When calling `getSession()` server side, you must pass the request object or you can the pass entire `context` object as it contains the `req` object. e.g. `getSession(context)` or `getSession({req})`
:::
---
@@ -239,17 +226,17 @@ The URL must be considered valid by the [redirect callback handler](http://local
Using the supplied React `<Provider>` allows instances of `useSession()` to share the session object across components, by using [React Context](https://reactjs.org/docs/context.html) under the hood.
This improves performance, reduces network calls and avoids page flicker when rendering.
This improves performance, reduces network calls and avoids page flicker when rendering. It is highly recommended and can be easily added to all pages in Next.js apps by using `pages/_app.js`.
It is highly recommended and can be easily added to all pages in Next.js apps by using `/pages/_app.js`.
It is also *required* if you want to use client methods like `getSession()` in server side functions like `getServerSideProp()` or `getInitialProps()`.
```jsx title="/pages/_app.js"
```jsx title="pages/_app.js"
import { Provider } from 'next-auth/client'
export default ({ Component, pageProps }) => {
const { session } = pageProps
return (
<Provider session={session}>
<Provider options={{ site: process.env.SITE }} session={session} >
<Component {...pageProps} />
</Provider>
)
@@ -258,6 +245,21 @@ export default ({ Component, pageProps }) => {
If you pass the `session` page prop to the `<Provider>` as in the example above you can avoid checking the session twice on pages that support both server and client side rendering.
### Options
* `site` (required) - The URL of the site (e.g. `http://localhost:3000`)
* `baseUrl` (optional) - The base URL for NextAuth.js (e.g. `/api/auth`)
* `clientMaxAge` (optional) - How often to refresh the session the background (in seconds)
When `clientMaxAge` is set to `0` (the default) sessions are not re-checked automatically, only when a new window or tab is opened or when `getSession()` is called. If set to any other value, specifies how many seconds the client should poll the server to check the session is valid and to keep it alive.
It can be useful to use this option to prevent sessions from timing out if your application has a short session expiry time. This option usually has cost implications as checking session status triggers a call to a server side route and/or a database.
:::tip
In NextAuth.js session state is automatically synchronized across all open windows and tabs in the same browser. If you have session expiry times of 30 days or more (the default) you probably don't need to use the `clientMaxAge` option, or can set it to a high value (e.g. every 24 hours).
:::
:::note
See [**the Next.js documentation**](https://nextjs.org/docs/advanced-features/custom-app) for more information on **_app.js** in Next.js applications.
:::

View File

@@ -17,7 +17,7 @@ You can find a live demo of the example project at [next-auth-example.now.sh](ht
To add NextAuth.js to a project, first create a file called `[...nextauth].js` in `pages/api/auth`.
```javascript title="/pages/api/auth/[...nextauth].js"
```javascript title="pages/api/auth/[...nextauth].js"
import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
@@ -49,7 +49,7 @@ See the [options documentation](/configuration/options) for how to configure pro
The `useSession()` React Hook in the NextAuth.js client is the easiest way to check if someone is signed in.
```jsx title="/pages/index.js"
```jsx title="pages/index.js"
import React from 'react'
import { useSession } from 'next-auth/client'

View File

@@ -27,7 +27,7 @@ NextAuth.js can be used with or without a database.
* An open source solution that allows you to keep control of your data
* Supports Bring Your Own Database (BYOD) and can be used with any database
* Built-in support for for [MySQL, MariaDB, Postgres, MongoDB and SQLite](/configuration/database)
* Built-in support for [MySQL, MariaDB, Postgres, MongoDB and SQLite](/configuration/database)
* Works great with databases from popular hosting providers
* Can also be used *without a database* (e.g. OAuth + JWT)

View File

@@ -3,16 +3,15 @@ id: apple
title: Apple
---
## API Documentation
## Documentation
https://developer.apple.com/sign-in-with-apple/get-started/
## App Configuration
## Configuration
https://developer.apple.com/account/resources/identifiers/list/serviceId
## Usage
## Example
There are two ways you can use the Sign in with Apple provider.

View File

@@ -3,15 +3,19 @@ id: auth0
title: Auth0
---
## API Documentation
## Documentation
https://auth0.com/docs/api/authentication#authorize-application
## App Configuration
## Configuration
https://manage.auth0.com/dashboard
## Usage
:::tip
Configure your application in Auth0 as a 'Regular Web Application' (not a 'Single Page App').
:::
## Example
```js
import Providers from `next-auth/providers`
@@ -20,8 +24,12 @@ providers: [
Providers.Auth0({
clientId: process.env.AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET,
subdomain: process.env.AUTH0_SUBDOMAIN
domain: process.env.AUTH0_DOMAIN
})
}
...
```
```
:::note
`domain` should be the fully qualified domain  e.g. `dev-s6clz2lv.eu.auth0.com`
:::

View File

@@ -0,0 +1,27 @@
---
id: battle.net
title: Battle.net
---
## Documentation
https://develop.battle.net/documentation/guides/using-oauth
## Configuration
https://develop.battle.net/access/clients
## Example
```js
import Providers from `next-auth/providers`
...
providers: [
Providers.BattleNet({
clientId: process.env.BATTLENET_CLIENT_ID,
clientSecret: process.env.BATTLENET_CLIENT_SECRET,
region: process.env.BATTLENET_REGION
})
}
...
```

View File

@@ -3,15 +3,15 @@ id: box
title: Box
---
## API Documentation
## Documentation
https://developer.box.com/reference/
## App Configuration
## Configuration
https://developer.box.com/guides/sso-identities-and-app-users/connect-okta-to-app-users/configure-box/
## Usage
## Example
```js
import Providers from `next-auth/providers`

View File

@@ -0,0 +1,35 @@
---
id: cognito
title: Amazon Cognito
---
## Documentation
https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-userpools-server-contract-reference.html
## Configuration
https://console.aws.amazon.com/cognito/users/
You need to select your AWS region to go the the Cognito dashboard.
## Example
```js
import Providers from `next-auth/providers`
...
providers: [
Providers.Cognito({
clientId: process.env.COGNITO_CLIENT_ID,
clientSecret: process.env.COGNITO_CLIENT_SECRET,
domain: process.env.COGNITO_DOMAIN,
})
}
...
```
warning:::
Make sure you select all the appropriate client settings or the OAuth flow will not work.
:::
![cognito](https://user-images.githubusercontent.com/7902980/83951604-cd096e80-a832-11ea-8bd2-c496ec9a16cb.PNG)

View File

@@ -27,7 +27,7 @@ It comes with the constraint that users authenticated in this manner are not per
The functionality provided for credentials based authentication is intentionally limited to discourage use of passwords due to the inherent security risks associated with them and the additional complexity associated with supporting usernames and passwords.
:::
## Usage
## Example
The Credentials provider is specified like other providers, except that you need to define a handler for `authorize()` that accepts credentials input and returns either a `user` object or `false`.
@@ -35,7 +35,7 @@ If you return an object it will be persisted to the JSON Web Token and the user
If you return `false` or `null` then an error will be displayed advising the user to check their details.
```js title="/pages/api/auth/[...nextauth].js"
```js title="pages/api/auth/[...nextauth].js"
import Providers from `next-auth/providers`
...
providers: [
@@ -65,7 +65,7 @@ providers: [
}
}
})
}
]
...
```
@@ -73,7 +73,7 @@ To use your new credentials provider, you will need to create a form that posts
All form parameters submitted will be passed as `credentials` to your `authorize` callback.
```js title="/pages/signin"
```js title="pages/signin"
import React from 'react'
export default () => {

View File

@@ -3,15 +3,15 @@ id: discord
title: Discord
---
## API Documentation
## Documentation
https://discord.com/developers/docs/topics/oauth2
## App Configuration
## Configuration
https://discord.com/developers/applications
## Usage
## Example
```js
import Providers from `next-auth/providers`

View File

@@ -39,7 +39,7 @@ The Email Provider can be used with both JSON Web Tokens and database sessions,
Now you can add the email provider like this:
```js {3} title="/pages/api/auth/[...nextauth].js"
```js {3} title="pages/api/auth/[...nextauth].js"
providers: [
Providers.Email({
server: process.env.EMAIL_SERVER,
@@ -61,7 +61,7 @@ The Email Provider can be used with both JSON Web Tokens and database sessions,
```
Now you can add the provider settings to the NextAuth options object in the Email Provider.
```js title="/pages/api/auth/[...nextauth].js"
```js title="pages/api/auth/[...nextauth].js"
providers: [
Providers.Email({
server: {

View File

@@ -3,15 +3,15 @@ id: facebook
title: Facebook
---
## API Documentation
## Documentation
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/
## App Configuration
## Configuration
https://developers.facebook.com/apps/
## Usage
## Example
```js
import Providers from `next-auth/providers`

View File

@@ -3,15 +3,15 @@ id: github
title: GitHub
---
## API Documentation
## Documentation
https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps
## App Configuration
## Configuration
https://github.com/settings/apps
## Usage
## Example
```js
import Providers from `next-auth/providers`
@@ -23,7 +23,8 @@ providers: [
})
}
...
```
:::warning
Only allows one callback URL. May not return email address if privacy enabled.
Only allows one callback URL per Client ID + Secret. May not return email address if privacy enabled.
:::

View File

@@ -3,15 +3,15 @@ id: gitlab
title: GitLab
---
## API Documentation
## Documentation
https://docs.gitlab.com/ee/api/oauth2.html
## App Configuration
## Configuration
https://gitlab.com/profile/applications
## Usage
## Example
```js
import Providers from `next-auth/providers`
@@ -24,6 +24,7 @@ providers: [
}
...
```
:::tip
Enable the *"read_user"* option in scope if you want to save the users email address on sign up.
:::

View File

@@ -3,15 +3,15 @@ id: google
title: Google
---
## API Documentation
## Documentation
https://developers.google.com/identity/protocols/oauth2
## App Configuration
## Configuration
https://console.developers.google.com/apis/credentials
## Usage
## Example
```js
import Providers from `next-auth/providers`

View File

@@ -3,15 +3,12 @@ id: identity-server4
title: IdentityServer4
---
## API Documentation
## Documentation
https://identityserver4.readthedocs.io/en/latest/
## App Configuration
## Usage
## Example
```js
import Providers from `next-auth/providers`

View File

@@ -3,15 +3,15 @@ id: mixer
title: Mixer
---
## API Documentation
## Documentation
https://dev.mixer.com/reference/oauth
## App Configuration
## Configuration
https://mixer.com/lab/oauth
## Usage
## Example
```js
import Providers from `next-auth/providers`

View File

@@ -3,15 +3,11 @@ id: okta
title: Okta
---
## API Documentation
## Documentation
https://developer.okta.com/docs/reference/api/oidc
## App Configuration
## Usage
## Example
```js
import Providers from `next-auth/providers`

View File

@@ -3,15 +3,15 @@ id: slack
title: Slack
---
## API Documentation
## Documentation
https://api.slack.com
## App Configuration
## Configuration
https://api.slack.com/apps
## Usage
## Example
```js
import Providers from `next-auth/providers`

View File

@@ -3,15 +3,15 @@ id: twitch
title: Twitch
---
## API Documentation
## Documentation
https://dev.twitch.tv/docs/authentication
## App Configuration
## Configuration
https://dev.twitch.tv/console/apps
## Usage
## Example
```js
import Providers from `next-auth/providers`

View File

@@ -3,15 +3,15 @@ id: twitter
title: Twitter
---
## API Documentation
## Documentation
https://developer.twitter.com
## App Configuration
## Configuration
https://developer.twitter.com/en/apps
## Usage
## Example
```js
import Providers from `next-auth/providers`

View File

@@ -3,15 +3,15 @@ id: yandex
title: Yandex
---
## API Documentation
## Documentation
https://tech.yandex.com/oauth/doc/dg/concepts/about-docpage/
## App Configuration
## Configuration
https://oauth.yandex.com/client/new
## Usage
## Example
```js
import Providers from `next-auth/providers`

View File

@@ -11,12 +11,15 @@ module.exports = {
'configuration/providers',
'configuration/database',
'configuration/pages',
'configuration/callbacks'
'configuration/callbacks',
'configuration/events'
],
'Authentication Providers': [
'providers/apple',
'providers/auth0',
'providers/battle.net',
'providers/box',
'providers/cognito',
'providers/discord',
'providers/email',
'providers/credentials',

View File

@@ -107,6 +107,10 @@ html[data-theme='dark'] .hero {
background: linear-gradient(0deg, rgba(222,222,222,0.075) 0%, rgba(255,255,255,0) 100%);
}
.hero .container {
margin-bottom: 2rem;
}
.hero .hero__title {
font-size: 3rem;
margin-bottom: 0.5rem;
@@ -128,10 +132,6 @@ html[data-theme='dark'] .hero {
.hero .hero__subtitle {
font-size: 1.5rem;
}
.hero .container {
margin-bottom: 2rem;
}
}
.home-subtitle {

View File

@@ -109,7 +109,7 @@ function Home () {
<section className={`section-features ${styles.features}`}>
<div className='container'>
<h2 className='text--center'>
Full stack open source authentication
Open Source Authentication
</h2>
<div className='row'>
{features.map((props, idx) => (
@@ -150,8 +150,8 @@ function Home () {
<p className='text--center'>
<Link
to='/getting-started/example'
className='button button--secondary button--ouline button--lg rounded-pill'
>Example Code
className='button button--primary button--ouline button--lg rounded-pill'
>View Example Code
</Link>
</p>
</div>
@@ -197,7 +197,7 @@ import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
const options = {
site: 'https://example.com'
site: 'https://example.com',
providers: [
// OAuth authentication providers
Providers.Apple({

View File

@@ -57,6 +57,7 @@
.features h2 {
font-size: 2rem;
line-height: 3rem;
margin: 2rem 0 4rem 0;
}