Compare commits

...

11 Commits

Author SHA1 Message Date
Balázs Orbán
782482b9f4 feat: make tokens available in profile callback (#1329)
* feat: make access_token available in profile callback

* docs(provider): mention access_token param in profile callback

* feat: send all available tokens to provider.profile
2021-02-20 22:58:48 +01:00
Balázs Orbán
2d364f246a docs: tweak release badges 2021-02-17 19:14:45 +01:00
Balázs Orbán
564b342f69 fix(docs): generate providers on docosaurus start 2021-02-16 15:42:27 +01:00
Balázs Orbán
63638d81dc docs: add sponsoring information 2021-02-16 15:42:27 +01:00
Balázs Orbán
28683015f1 docs: add links to README badges 2021-02-16 10:34:54 +01:00
Balázs Orbán
726c49603d chore: make next a prerelease channel 2021-02-16 10:20:46 +01:00
Balázs Orbán
a7113c6d3e chore: trigger release on main branch 2021-02-16 09:50:19 +01:00
Balázs Orbán
910514c6e2 chore: trigger release action on next branch 2021-02-15 21:51:17 +01:00
Balázs Orbán
b7cca484cf docs(provider): mention re-exporting config 2021-02-15 13:28:20 +01:00
Balázs Orbán
e293e786a8 fix(page): fallback to default error when no query param (#1303) 2021-02-11 22:25:09 +01:00
Balázs Orbán
82dd6ba3e4 feat(logger): introduce user configurable logger (#1294) 2021-02-11 14:50:53 +01:00
19 changed files with 219 additions and 65 deletions

View File

@@ -2,8 +2,10 @@ name: Release
on:
push:
branches:
- main
- canary
- 'main'
- 'next'
- '3.x'
pull_request:
jobs:
release:
name: 'Release'
@@ -21,4 +23,4 @@ jobs:
- run: npx semantic-release@17
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
NPM_TOKEN: ${{secrets.NPM_TOKEN}}
NPM_TOKEN: ${{secrets.NPM_TOKEN}}

3
FUNDING.yml Normal file
View File

@@ -0,0 +1,3 @@
# https://docs.github.com/en/github/administering-a-repository/displaying-a-sponsor-button-in-your-repository
github: [balazsorban44]

View File

@@ -7,12 +7,25 @@
Open Source. Full Stack. Own Your Data.
</p>
<p align="center" style="align: center;">
<img src="https://github.com/nextauthjs/next-auth/workflows/Build%20Test/badge.svg" alt="Build Test" />
<img src="https://github.com/nextauthjs/next-auth/workflows/Integration%20Test/badge.svg" alt="Integration Test" />
<img src="https://img.shields.io/bundlephobia/minzip/next-auth" alt="Bundle Size"/>
<img src="https://img.shields.io/npm/dm/next-auth" alt="Downloads" />
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth" alt="Github Stars" />
<img src="https://img.shields.io/github/v/release/nextauthjs/next-auth?include_prereleases" alt="Github Release" />
<a href="https://github.com/nextauthjs/next-auth/actions?query=workflow%3ARelease">
<img src="https://github.com/nextauthjs/next-auth/workflows/Release/badge.svg" alt="Release" />
</a>
<a href="https://github.com/nextauthjs/next-auth/actions?query=workflow%3A%22Integration+Test%22">
<img src="https://github.com/nextauthjs/next-auth/workflows/Integration%20Test/badge.svg" alt="Integration Test" />
</a>
<a href="https://bundlephobia.com/result?p=next-auth">
<img src="https://img.shields.io/bundlephobia/minzip/next-auth" alt="Bundle Size"/>
</a>
<a href="https://www.npmtrends.com/next-auth">
<img src="https://img.shields.io/npm/dm/next-auth" alt="Downloads" />
</a>
<a href="https://github.com/nextauthjs/next-auth/stargazers">
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth" alt="Github Stars" />
</a>
<a href="https://www.npmjs.com/package/next-auth">
<img src="https://img.shields.io/github/v/release/nextauthjs/next-auth?label=latest" alt="Github Stable Release" />
</a>
<img src="https://img.shields.io/github/v/release/nextauthjs/next-auth?include_prereleases&label=prerelease&sort=semver" alt="Github Prelease" />
</p>
</p>
@@ -154,4 +167,3 @@ We're open to all community contributions! If you'd like to contribute in any wa
## License
ISC

View File

@@ -108,5 +108,11 @@
"globals": [
"fetch"
]
}
},
"funding": [
{
"type" : "github",
"url" : "https://github.com/sponsors/balazsorban44"
}
]
}

View File

@@ -2,9 +2,6 @@ module.exports = {
branches: [
'+([0-9])?(.{+([0-9]),x}).x',
'main',
'next',
'next-major',
{ name: 'beta', prerelease: true },
{ name: 'alpha', prerelease: true }
{ name: 'next', prerelease: true }
]
}

View File

@@ -1,84 +1,83 @@
const Adapter = (config, options = {}) => {
async function getAdapter (appOptions) {
const { logger } = appOptions
// Display debug output if debug option enabled
function _debug (...args) {
if (appOptions.debug) {
console.log('[next-auth][debug]', ...args)
}
function debug (debugCode, ...args) {
logger.debug(`ADAPTER_${debugCode}`, ...args)
}
async function createUser (profile) {
_debug('createUser', profile)
debug('createUser', profile)
return null
}
async function getUser (id) {
_debug('getUser', id)
debug('getUser', id)
return null
}
async function getUserByEmail (email) {
_debug('getUserByEmail', email)
debug('getUserByEmail', email)
return null
}
async function getUserByProviderAccountId (providerId, providerAccountId) {
_debug('getUserByProviderAccountId', providerId, providerAccountId)
debug('getUserByProviderAccountId', providerId, providerAccountId)
return null
}
async function updateUser (user) {
_debug('updateUser', user)
debug('updateUser', user)
return null
}
async function deleteUser (userId) {
_debug('deleteUser', userId)
debug('deleteUser', userId)
return null
}
async function linkAccount (userId, providerId, providerType, providerAccountId, refreshToken, accessToken, accessTokenExpires) {
_debug('linkAccount', userId, providerId, providerType, providerAccountId, refreshToken, accessToken, accessTokenExpires)
debug('linkAccount', userId, providerId, providerType, providerAccountId, refreshToken, accessToken, accessTokenExpires)
return null
}
async function unlinkAccount (userId, providerId, providerAccountId) {
_debug('unlinkAccount', userId, providerId, providerAccountId)
debug('unlinkAccount', userId, providerId, providerAccountId)
return null
}
async function createSession (user) {
_debug('createSession', user)
debug('createSession', user)
return null
}
async function getSession (sessionToken) {
_debug('getSession', sessionToken)
debug('getSession', sessionToken)
return null
}
async function updateSession (session, force) {
_debug('updateSession', session)
debug('updateSession', session)
return null
}
async function deleteSession (sessionToken) {
_debug('deleteSession', sessionToken)
debug('deleteSession', sessionToken)
return null
}
async function createVerificationRequest (identifier, url, token, secret, provider) {
_debug('createVerificationRequest', identifier)
debug('createVerificationRequest', identifier)
return null
}
async function getVerificationRequest (identifier, token, secret, provider) {
_debug('getVerificationRequest', identifier, token)
debug('getVerificationRequest', identifier, token)
return null
}
async function deleteVerificationRequest (identifier, token, secret, provider) {
_debug('deleteVerification', identifier, token)
debug('deleteVerification', identifier, token)
return null
}

View File

@@ -1,7 +1,6 @@
import { createHash, randomBytes } from 'crypto'
import { CreateUserError } from '../../lib/errors'
import logger from '../../lib/logger'
const Adapter = (config) => {
const {
@@ -21,6 +20,7 @@ const Adapter = (config) => {
}
async function getAdapter (appOptions) {
const { logger } = appOptions
function debug (debugCode, ...args) {
logger.debug(`PRISMA_${debugCode}`, ...args)
}

View File

@@ -6,7 +6,7 @@ import { CreateUserError } from '../../lib/errors'
import adapterConfig from './lib/config'
import adapterTransform from './lib/transform'
import Models from './models'
import logger from '../../lib/logger'
import { updateConnectionEntities } from './lib/utils'
const Adapter = (typeOrmConfig, options = {}) => {
@@ -41,6 +41,12 @@ const Adapter = (typeOrmConfig, options = {}) => {
let connection = null
async function getAdapter (appOptions) {
const { logger } = appOptions
// Display debug output if debug option enabled
function debug (debugCode, ...args) {
logger.debug(`TYPEORM_${debugCode}`, ...args)
}
// Helper function to reuse / restablish connections
// (useful if they drop when after being idle)
async function _connect () {
@@ -77,12 +83,6 @@ const Adapter = (typeOrmConfig, options = {}) => {
// https://github.com/typeorm/typeorm/blob/master/docs/entity-manager-api.md
const { manager } = connection
// Display debug output if debug option enabled
// @TODO Refactor logger so is passed in appOptions
function debug (debugCode, ...args) {
logger.debug(`TYPEORM_${debugCode}`, ...args)
}
// The models are primarily designed for ANSI SQL database, but some
// flexiblity is required in the adapter to support non-SQL databases such
// as MongoDB which have different pragmas.

View File

@@ -11,7 +11,7 @@
// We use HTTP POST requests with CSRF Tokens to protect against CSRF attacks.
import { useState, useEffect, useContext, createContext, createElement } from 'react'
import logger from '../lib/logger'
import _logger, { proxyLogger } from '../lib/logger'
import parseUrl from '../lib/parse-url'
// This behaviour mirrors the default behaviour for getting the site name that
@@ -37,6 +37,8 @@ const __NEXTAUTH = {
_getSession: () => {}
}
const logger = proxyLogger(_logger, __NEXTAUTH.basePath)
// Add event listners on load
if (typeof window !== 'undefined') {
if (__NEXTAUTH._eventListenersAdded === false) {

5
src/lib/logger.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
export interface LoggerInstance {
warn: (code?: string, ...message: unknown[]) => void
error: (code?: string, ...message: unknown[]) => void
debug: (code?: string, ...message: unknown[]) => void
}

View File

@@ -1,4 +1,5 @@
const logger = {
/** @type {import("./logger").LoggerInstance} */
const _logger = {
error (code, ...message) {
console.error(
`[next-auth][error][${code.toLowerCase()}]`,
@@ -22,4 +23,60 @@ const logger = {
}
}
export default logger
/**
* Override the built-in logger.
* Any `undefined` level will use the default logger.
* @param {Partial<import("./logger").LoggerInstance>} newLogger
*/
export function setLogger (newLogger = {}) {
if (newLogger.error) _logger.error = newLogger.error
if (newLogger.warn) _logger.warn = newLogger.warn
if (newLogger.debug) _logger.debug = newLogger.debug
}
export default _logger
/**
* Serializes client-side log messages and sends them to the server
* @param {import("./logger").LoggerInstance} logger
* @param {string} basePath
* @return {import("./logger").LoggerInstance}
*/
export function proxyLogger (logger = _logger, basePath) {
try {
if (typeof window === 'undefined') {
return logger
}
const clientLogger = {}
for (const level in logger) {
clientLogger[level] = (code, ...message) => {
_logger[level](code, ...message) // Log on client as usual
const url = `${basePath}/_log`
const body = new URLSearchParams({
level,
code,
message: JSON.stringify(message.map(m => {
if (m instanceof Error) {
// Serializing errors: https://iaincollins.medium.com/error-handling-in-javascript-a6172ccdf9af
return { name: m.name, message: m.message, stack: m.stack }
}
return m
}))
})
if (navigator.sendBeacon) {
return navigator.sendBeacon(url, body)
}
return fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body
})
}
}
return clientLogger
} catch {
return _logger
}
}

View File

@@ -1,4 +1,5 @@
import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
import { LoggerInstance } from 'src/lib/logger'
import { CallbacksOptions } from './lib/callbacks'
import { CookiesOptions } from './lib/cookie'
import { EventsOptions } from './lib/events'
@@ -59,10 +60,12 @@ export interface NextAuthOptions {
useSecureCookies?: boolean
/** @docs https://next-auth.js.org/configuration/options#cookies */
cookies?: CookiesOptions
/** @docs https://next-auth.js.org/configuration/options#logger */
logger: LoggerInstance
}
/** Options that are the same both in internal and user provided options. */
export type NextAuthSharedOptions = 'pages' | 'jwt' | 'events' | 'callbacks' | 'cookies' | 'secret' | 'adapter' | 'theme' | 'debug'
export type NextAuthSharedOptions = 'pages' | 'jwt' | 'events' | 'callbacks' | 'cookies' | 'secret' | 'adapter' | 'theme' | 'debug' | 'logger'
export interface NextAuthInternalOptions extends Pick<NextAuthOptions, NextAuthSharedOptions> {
pkce?: {

View File

@@ -1,7 +1,7 @@
import adapters from '../adapters'
import jwt from '../lib/jwt'
import parseUrl from '../lib/parse-url'
import logger from '../lib/logger'
import logger, { setLogger } from '../lib/logger'
import * as cookie from './lib/cookie'
import * as defaultEvents from './lib/default-events'
import * as defaultCallbacks from './lib/default-callbacks'
@@ -27,6 +27,9 @@ if (!process.env.NEXTAUTH_URL) {
* @param {import(".").NextAuthOptions} userOptions
*/
async function NextAuthHandler (req, res, userOptions) {
if (userOptions.logger) {
setLogger(userOptions.logger)
}
// If debug enabled, set ENV VAR so that logger logs debug messages
if (userOptions.debug) {
process.env._NEXTAUTH_DEBUG = true
@@ -127,7 +130,8 @@ async function NextAuthHandler (req, res, userOptions) {
...defaultCallbacks,
...userOptions.callbacks
},
pkce: {}
pkce: {},
logger
}
await callbackUrlHandler(req, res)
@@ -220,6 +224,21 @@ async function NextAuthHandler (req, res, userOptions) {
return routes.callback(req, res)
}
break
case '_log':
try {
if (!userOptions.logger) return
const {
code = 'CLIENT_ERROR',
level = 'error',
message = '[]'
} = req.body
logger[level](code, ...JSON.parse(message))
} catch (error) {
// If logging itself failed...
logger.error('LOGGER_ERROR', error)
}
return res.end()
default:
}
}

View File

@@ -108,7 +108,7 @@ async function getProfile ({ profileData, tokens, provider, user }) {
logger.debug('PROFILE_DATA', profileData)
const profile = await provider.profile(profileData)
const profile = await provider.profile(profileData, tokens)
// Return profile, raw profile and auth provider details
return {
profile: {

View File

@@ -1,8 +1,17 @@
// @ts-check
import { h } from 'preact' // eslint-disable-line no-unused-vars
import render from 'preact-render-to-string'
/** Renders an error page. */
export default function error ({ baseUrl, basePath, error, res }) {
/**
* Renders an error page.
* @param {{
* baseUrl: string
* basePath: string
* error?: string
* res: import("..").NextAuthResponse
* }} params
*/
export default function error ({ baseUrl, basePath, error = 'default', res }) {
const signinPageUrl = `${baseUrl}${basePath}/signin`
const errors = {
@@ -44,7 +53,7 @@ export default function error ({ baseUrl, basePath, error, res }) {
}
}
const { statusCode, heading, message, signin } = errors[error.toLowerCase()] || errors.default
const { statusCode, heading, message, signin } = errors[error.toLowerCase()]
res.status(statusCode)

View File

@@ -307,6 +307,42 @@ Set debug to `true` to enable debug messages for authentication and database ope
---
### logger
* **Default value**: `console`
* **Required**: *No*
#### Description
Override any of the logger levels (`undefined` levels will use the built-in logger), and intercept logs in NextAuth. You can use this to send NextAuth logs to a third-party logging service.
Example:
```js title="/pages/api/auth/[...nextauth].js"
import log from "logging-service"
export default NextAuth({
...
logger: {
error(code, ...message) {
log.error(code, message)
},
warn(code, ...message) {
log.warn(code, message)
}
debug(code, ...message) {
log.debug(code, message)
}
}
...
})
```
:::note
If the `debug` level is defined by the user, it will be called regardless of the `debug: false` [option](#debug).
:::
---
### theme
* **Default value**: `"auto"`

View File

@@ -78,7 +78,10 @@ As an example of what this looks like, this is the the provider object returned
requestTokenUrl: "https://accounts.google.com/o/oauth2/auth",
authorizationUrl: "https://accounts.google.com/o/oauth2/auth?response_type=code",
profileUrl: "https://www.googleapis.com/oauth2/v1/userinfo?alt=json",
async profile(profile) {
async profile(profile, tokens) {
// You can use the tokens, in case you want to fetch more profile information
// For example several OAuth provider does not return e-mail by default.
// Depending on your provider, will have tokens like `access_token`, `id_token` and or `refresh_token`
return {
id: profile.id,
name: profile.name,
@@ -113,9 +116,10 @@ providers: [
```
:::tip
If you think your custom provider might be useful to others, we encourage you to open a PR and add it to the built-in list so others can discover it much more easily! You only need to add two files:
1. Your config: [`src/providers/{provider}.js`](https://github.com/nextauthjs/next-auth/tree/main/src/providers)
2. Provider documentation: [`www/docs/providers/{provider}.md`](https://github.com/nextauthjs/next-auth/tree/main/www/docs/providers)
If you think your custom provider might be useful to others, we encourage you to open a PR and add it to the built-in list so others can discover it much more easily! You only need to add three changes:
1. Add your config: [`src/providers/{provider}.js`](https://github.com/nextauthjs/next-auth/tree/main/src/providers)
2. Re-export your config: at [`src/providers/index.js`](https://github.com/nextauthjs/next-auth/blob/main/src/providers/index.js)
3. Add provider documentation: [`www/docs/providers/{provider}.md`](https://github.com/nextauthjs/next-auth/tree/main/www/docs/providers)
You can look at the existing built-in providers for inspiration.
:::

View File

@@ -5,14 +5,14 @@ title: Contributors
## Core Team
* <a href="https://github.com/iaincollins">Iain Collins</a>
* <a href="https://github.com/LoriKarikari">Lori Karikari</a>
* <a href="https://github.com/ndom91">Nico Domino</a>
* <a href="https://github.com/Fumler">Fredrik Pettersen</a>
* <a href="https://github.com/geraldnolan">Gerald Nolan</a>
* <a href="https://github.com/lluia">Lluis Agusti</a>
* <a href="https://github.com/JeffersonBledsoe">Jefferson Bledsoe</a>
* <a href="https://github.com/balazsorban44">Balázs Orbán</a>
* [Iain Collins](https://github.com/iaincollins)
* [Lori Karikari](https://github.com/LoriKarikari)
* [Nico Domino](https://github.com/ndom91)
* [Fredrik Pettersen](https://github.com/Fumler)
* [Gerald Nolan](https://github.com/geraldnolan)
* [Lluis Agusti](https://github.com/lluia)
* [Jefferson Bledsoe](https://github.com/JeffersonBledsoe)
* [Balázs Orbán](https://github.com/sponsors/balazsorban44)
_Special thanks to Lori Karikari for creating most of the providers, to Nico Domino for creating this site, to Fredrik Pettersen for creating the Prisma adapter, to Gerald Nolan for adding support for Sign in with Apple, to Lluis Agusti for work to add TypeScript definitions and to Jefferson Bledsoe for working on automating testing._

View File

@@ -2,7 +2,7 @@
"name": "next-auth-docs",
"version": "0.1.1",
"scripts": {
"start": "docusaurus start",
"start": "npm run generate-providers && docusaurus start",
"build": "npm run generate-providers && docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",