1
- import adapters from ' ../adapters'
2
- import jwt from ' ../lib/jwt'
3
- import parseUrl from ' ../lib/parse-url'
4
- import logger , { setLogger } from ' ../lib/logger'
5
- import * as cookie from ' ./lib/cookie'
6
- import * as defaultEvents from ' ./lib/default-events'
7
- import * as defaultCallbacks from ' ./lib/default-callbacks'
8
- import parseProviders from ' ./lib/providers'
9
- import * as routes from ' ./routes'
10
- import renderPage from ' ./pages'
11
- import createSecret from ' ./lib/create-secret'
12
- import callbackUrlHandler from ' ./lib/callback-url-handler'
13
- import extendRes from ' ./lib/extend-res'
14
- import csrfTokenHandler from ' ./lib/csrf-token-handler'
15
- import * as pkce from ' ./lib/oauth/pkce-handler'
16
- import * as state from ' ./lib/oauth/state-handler'
1
+ import adapters from " ../adapters"
2
+ import jwt from " ../lib/jwt"
3
+ import parseUrl from " ../lib/parse-url"
4
+ import logger , { setLogger } from " ../lib/logger"
5
+ import * as cookie from " ./lib/cookie"
6
+ import * as defaultEvents from " ./lib/default-events"
7
+ import * as defaultCallbacks from " ./lib/default-callbacks"
8
+ import parseProviders from " ./lib/providers"
9
+ import * as routes from " ./routes"
10
+ import renderPage from " ./pages"
11
+ import createSecret from " ./lib/create-secret"
12
+ import callbackUrlHandler from " ./lib/callback-url-handler"
13
+ import extendRes from " ./lib/extend-res"
14
+ import csrfTokenHandler from " ./lib/csrf-token-handler"
15
+ import * as pkce from " ./lib/oauth/pkce-handler"
16
+ import * as state from " ./lib/oauth/state-handler"
17
17
18
18
// To work properly in production with OAuth providers the NEXTAUTH_URL
19
19
// environment variable must be set.
20
20
if ( ! process . env . NEXTAUTH_URL ) {
21
- logger . warn ( ' NEXTAUTH_URL' , ' NEXTAUTH_URL environment variable not set' )
21
+ logger . warn ( " NEXTAUTH_URL" , " NEXTAUTH_URL environment variable not set" )
22
22
}
23
23
24
24
/**
25
25
* @param {import("next").NextApiRequest } req
26
26
* @param {import("next").NextApiResponse } res
27
27
* @param {import("types").NextAuthOptions } userOptions
28
28
*/
29
- async function NextAuthHandler ( req , res , userOptions ) {
29
+ async function NextAuthHandler ( req , res , userOptions ) {
30
30
if ( userOptions . logger ) {
31
31
setLogger ( userOptions . logger )
32
32
}
@@ -39,45 +39,64 @@ async function NextAuthHandler (req, res, userOptions) {
39
39
// to avoid early termination of calls to the serverless function
40
40
// (and then return that promise when we are done) - eslint
41
41
// complains but I'm not sure there is another way to do this.
42
- return new Promise ( async resolve => { // eslint-disable-line no-async-promise-executor
42
+ // eslint-disable-next-line no-async-promise-executor
43
+ return new Promise ( async ( resolve ) => {
43
44
extendRes ( req , res , resolve )
44
45
45
46
if ( ! req . query . nextauth ) {
46
- const error = 'Cannot find [...nextauth].js in pages/api/auth. Make sure the filename is written correctly.'
47
+ const error =
48
+ "Cannot find [...nextauth].js in pages/api/auth. Make sure the filename is written correctly."
47
49
48
- logger . error ( ' MISSING_NEXTAUTH_API_ROUTE_ERROR' , error )
50
+ logger . error ( " MISSING_NEXTAUTH_API_ROUTE_ERROR" , error )
49
51
return res . status ( 500 ) . end ( `Error: ${ error } ` )
50
52
}
51
53
52
54
const {
53
55
nextauth,
54
56
action = nextauth [ 0 ] ,
55
57
providerId = nextauth [ 1 ] ,
56
- error = nextauth [ 1 ]
58
+ error = nextauth [ 1 ] ,
57
59
} = req . query
58
60
59
61
// @todo refactor all existing references to baseUrl and basePath
60
- const { basePath, baseUrl } = parseUrl ( process . env . NEXTAUTH_URL || process . env . VERCEL_URL )
62
+ const { basePath, baseUrl } = parseUrl (
63
+ process . env . NEXTAUTH_URL || process . env . VERCEL_URL
64
+ )
61
65
62
66
const cookies = {
63
- ...cookie . defaultCookies ( userOptions . useSecureCookies || baseUrl . startsWith ( 'https://' ) ) ,
67
+ ...cookie . defaultCookies (
68
+ userOptions . useSecureCookies || baseUrl . startsWith ( "https://" )
69
+ ) ,
64
70
// Allow user cookie options to override any cookie settings above
65
- ...userOptions . cookies
71
+ ...userOptions . cookies ,
66
72
}
67
73
68
74
const secret = createSecret ( { userOptions, basePath, baseUrl } )
69
75
70
- const providers = parseProviders ( { providers : userOptions . providers , baseUrl, basePath } )
76
+ const providers = parseProviders ( {
77
+ providers : userOptions . providers ,
78
+ baseUrl,
79
+ basePath,
80
+ } )
71
81
const provider = providers . find ( ( { id } ) => id === providerId )
72
82
73
83
// Protection only works on OAuth 2.x providers
74
- if ( provider ?. type === 'oauth' && provider . version ?. startsWith ( '2' ) ) {
75
- // When provider.state is undefined, we still want this to pass
76
- if ( ! provider . protection && provider . state !== false ) {
77
- // Default to state, as we did in 3.1 REVIEW: should we use "pkce" or "none" as default?
78
- provider . protection = [ 'state' ]
79
- } else if ( typeof provider . protection === 'string' ) {
80
- provider . protection = [ provider . protection ]
84
+ // TODO:
85
+ // - rename to `checks` in 4.x, so it is similar to `openid-client`
86
+ // - stop supporting `protection` as string
87
+ // - remove `state` property
88
+ if ( provider ?. type === "oauth" && provider . version ?. startsWith ( "2" ) ) {
89
+ // Priority: (protection array > protection string) > state > default
90
+ if ( provider . protection ) {
91
+ provider . protection = Array . isArray ( provider . protection )
92
+ ? provider . protection
93
+ : [ provider . protection ]
94
+ } else if ( provider . state !== undefined ) {
95
+ provider . protection = [ provider . state ? "state" : "none" ]
96
+ } else {
97
+ // Default to state, as we did in 3.1
98
+ // REVIEW: should we use "pkce" or "none" as default?
99
+ provider . protection = [ "state" ]
81
100
}
82
101
}
83
102
@@ -86,14 +105,16 @@ async function NextAuthHandler (req, res, userOptions) {
86
105
// Parse database / adapter
87
106
// If adapter is provided, use it (advanced usage, overrides database)
88
107
// If database URI or config object is provided, use it (simple usage)
89
- const adapter = userOptions . adapter ?? ( userOptions . database && adapters . Default ( userOptions . database ) )
108
+ const adapter =
109
+ userOptions . adapter ??
110
+ ( userOptions . database && adapters . Default ( userOptions . database ) )
90
111
91
112
// User provided options are overriden by other options,
92
113
// except for the options with special handling above
93
114
req . options = {
94
115
debug : false ,
95
116
pages : { } ,
96
- theme : ' auto' ,
117
+ theme : " auto" ,
97
118
// Custom options override defaults
98
119
...userOptions ,
99
120
// These computed settings can have values in userOptions but we override them
@@ -111,28 +132,28 @@ async function NextAuthHandler (req, res, userOptions) {
111
132
jwt : ! adapter , // If no adapter specified, force use of JSON Web Tokens (stateless)
112
133
maxAge,
113
134
updateAge : 24 * 60 * 60 , // Sessions updated only if session is greater than this value (0 = always, 24*60*60 = every 24 hours)
114
- ...userOptions . session
135
+ ...userOptions . session ,
115
136
} ,
116
137
// JWT options
117
138
jwt : {
118
139
secret, // Use application secret if no keys specified
119
140
maxAge, // same as session maxAge,
120
141
encode : jwt . encode ,
121
142
decode : jwt . decode ,
122
- ...userOptions . jwt
143
+ ...userOptions . jwt ,
123
144
} ,
124
145
// Event messages
125
146
events : {
126
147
...defaultEvents ,
127
- ...userOptions . events
148
+ ...userOptions . events ,
128
149
} ,
129
150
// Callback functions
130
151
callbacks : {
131
152
...defaultCallbacks ,
132
- ...userOptions . callbacks
153
+ ...userOptions . callbacks ,
133
154
} ,
134
155
pkce : { } ,
135
- logger
156
+ logger,
136
157
}
137
158
138
159
csrfTokenHandler ( req , res )
@@ -141,64 +162,74 @@ async function NextAuthHandler (req, res, userOptions) {
141
162
const render = renderPage ( req , res )
142
163
const { pages } = req . options
143
164
144
- if ( req . method === ' GET' ) {
165
+ if ( req . method === " GET" ) {
145
166
switch ( action ) {
146
- case ' providers' :
167
+ case " providers" :
147
168
return routes . providers ( req , res )
148
- case ' session' :
169
+ case " session" :
149
170
return routes . session ( req , res )
150
- case ' csrf' :
171
+ case " csrf" :
151
172
return res . json ( { csrfToken : req . options . csrfToken } )
152
- case ' signin' :
173
+ case " signin" :
153
174
if ( pages . signIn ) {
154
- let signinUrl = `${ pages . signIn } ${ pages . signIn . includes ( '?' ) ? '&' : '?' } callbackUrl=${ req . options . callbackUrl } `
155
- if ( error ) { signinUrl = `${ signinUrl } &error=${ error } ` }
175
+ let signinUrl = `${ pages . signIn } ${
176
+ pages . signIn . includes ( "?" ) ? "&" : "?"
177
+ } callbackUrl=${ req . options . callbackUrl } `
178
+ if ( error ) {
179
+ signinUrl = `${ signinUrl } &error=${ error } `
180
+ }
156
181
return res . redirect ( signinUrl )
157
182
}
158
183
159
184
return render . signin ( )
160
- case ' signout' :
185
+ case " signout" :
161
186
if ( pages . signOut ) return res . redirect ( pages . signOut )
162
187
163
188
return render . signout ( )
164
- case ' callback' :
189
+ case " callback" :
165
190
if ( provider ) {
166
191
if ( await pkce . handleCallback ( req , res ) ) return
167
192
if ( await state . handleCallback ( req , res ) ) return
168
193
return routes . callback ( req , res )
169
194
}
170
195
break
171
- case ' verify-request' :
196
+ case " verify-request" :
172
197
if ( pages . verifyRequest ) {
173
198
return res . redirect ( pages . verifyRequest )
174
199
}
175
200
return render . verifyRequest ( )
176
- case ' error' :
201
+ case " error" :
177
202
if ( pages . error ) {
178
- return res . redirect ( `${ pages . error } ${ pages . error . includes ( '?' ) ? '&' : '?' } error=${ error } ` )
203
+ return res . redirect (
204
+ `${ pages . error } ${
205
+ pages . error . includes ( "?" ) ? "&" : "?"
206
+ } error=${ error } `
207
+ )
179
208
}
180
209
181
210
// These error messages are displayed in line on the sign in page
182
- if ( [
183
- 'Signin' ,
184
- 'OAuthSignin' ,
185
- 'OAuthCallback' ,
186
- 'OAuthCreateAccount' ,
187
- 'EmailCreateAccount' ,
188
- 'Callback' ,
189
- 'OAuthAccountNotLinked' ,
190
- 'EmailSignin' ,
191
- 'CredentialsSignin'
192
- ] . includes ( error ) ) {
211
+ if (
212
+ [
213
+ "Signin" ,
214
+ "OAuthSignin" ,
215
+ "OAuthCallback" ,
216
+ "OAuthCreateAccount" ,
217
+ "EmailCreateAccount" ,
218
+ "Callback" ,
219
+ "OAuthAccountNotLinked" ,
220
+ "EmailSignin" ,
221
+ "CredentialsSignin" ,
222
+ ] . includes ( error )
223
+ ) {
193
224
return res . redirect ( `${ baseUrl } ${ basePath } /signin?error=${ error } ` )
194
225
}
195
226
196
227
return render . error ( { error } )
197
228
default :
198
229
}
199
- } else if ( req . method === ' POST' ) {
230
+ } else if ( req . method === " POST" ) {
200
231
switch ( action ) {
201
- case ' signin' :
232
+ case " signin" :
202
233
// Verified CSRF Token required for all sign in routes
203
234
if ( req . options . csrfTokenVerified && provider ) {
204
235
if ( await pkce . handleSignin ( req , res ) ) return
@@ -207,16 +238,19 @@ async function NextAuthHandler (req, res, userOptions) {
207
238
}
208
239
209
240
return res . redirect ( `${ baseUrl } ${ basePath } /signin?csrf=true` )
210
- case ' signout' :
241
+ case " signout" :
211
242
// Verified CSRF Token required for signout
212
243
if ( req . options . csrfTokenVerified ) {
213
244
return routes . signout ( req , res )
214
245
}
215
246
return res . redirect ( `${ baseUrl } ${ basePath } /signout?csrf=true` )
216
- case ' callback' :
247
+ case " callback" :
217
248
if ( provider ) {
218
249
// Verified CSRF Token required for credentials providers only
219
- if ( provider . type === 'credentials' && ! req . options . csrfTokenVerified ) {
250
+ if (
251
+ provider . type === "credentials" &&
252
+ ! req . options . csrfTokenVerified
253
+ ) {
220
254
return res . redirect ( `${ baseUrl } ${ basePath } /signin?csrf=true` )
221
255
}
222
256
@@ -225,31 +259,33 @@ async function NextAuthHandler (req, res, userOptions) {
225
259
return routes . callback ( req , res )
226
260
}
227
261
break
228
- case ' _log' :
262
+ case " _log" :
229
263
if ( userOptions . logger ) {
230
264
try {
231
265
const {
232
- code = ' CLIENT_ERROR' ,
233
- level = ' error' ,
234
- message = '[]'
266
+ code = " CLIENT_ERROR" ,
267
+ level = " error" ,
268
+ message = "[]" ,
235
269
} = req . body
236
270
237
271
logger [ level ] ( code , ...JSON . parse ( message ) )
238
272
} catch ( error ) {
239
273
// If logging itself failed...
240
- logger . error ( ' LOGGER_ERROR' , error )
274
+ logger . error ( " LOGGER_ERROR" , error )
241
275
}
242
276
}
243
277
return res . end ( )
244
278
default :
245
279
}
246
280
}
247
- return res . status ( 400 ) . end ( `Error: HTTP ${ req . method } is not supported for ${ req . url } ` )
281
+ return res
282
+ . status ( 400 )
283
+ . end ( `Error: HTTP ${ req . method } is not supported for ${ req . url } ` )
248
284
} )
249
285
}
250
286
251
287
/** Tha main entry point to next-auth */
252
- export default function NextAuth ( ...args ) {
288
+ export default function NextAuth ( ...args ) {
253
289
if ( args . length === 1 ) {
254
290
return ( req , res ) => NextAuthHandler ( req , res , args [ 0 ] )
255
291
}
0 commit comments