From b5dc4943a48a6ed38aafb7fecc0689082b86b88d Mon Sep 17 00:00:00 2001 From: Thisen Date: Tue, 14 Sep 2021 21:55:15 +0200 Subject: [PATCH 01/10] WIP strict types --- package-lock.json | 1 + package.json | 3 ++- src/server/pages/error.tsx | 36 +++++++++++++++++++---------- src/server/pages/signin.tsx | 14 +++++++++-- src/server/pages/types.ts | 13 +++++++++++ src/server/pages/verify-request.tsx | 6 ++++- tsconfig.json | 2 +- 7 files changed, 58 insertions(+), 17 deletions(-) create mode 100644 src/server/pages/types.ts diff --git a/package-lock.json b/package-lock.json index 5f880217ba..6f879b0ac4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "requires": true, "packages": { "": { + "name": "next-auth", "version": "0.0.0-semantically-released", "funding": [ { diff --git a/package.json b/package.json index fdba1f043b..dfc2162736 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,8 @@ "lint": "eslint .", "lint:fix": "eslint . --fix", "version:pr": "node ./config/version-pr", - "generate-providers": "node ./config/generate-providers.js" + "generate-providers": "node ./config/generate-providers.js", + "types": "tsc --noEmit --EmitDeclarationOnly false" }, "files": [ "lib", diff --git a/src/server/pages/error.tsx b/src/server/pages/error.tsx index 828ee5a37d..ef4096acef 100644 --- a/src/server/pages/error.tsx +++ b/src/server/pages/error.tsx @@ -1,16 +1,28 @@ -/** - * Renders an error page. - * @param {{ - * baseUrl: string - * basePath: string - * error?: string - * res: import("src/lib/types").NextAuthResponse - * }} params - */ -export default function Error({ baseUrl, basePath, error = "default", res }) { +import type { NextAuthResponse } from "src/lib/types" + +export interface ErrorServerPageParams { + baseUrl: string + basePath: string + error?: string + res: NextAuthResponse +} + +interface ErrorView { + statusCode: number + heading: string + message: JSX.Element + signin?: JSX.Element +} + +export default function Error({ + baseUrl, + basePath, + error = "default", + res, +}: ErrorServerPageParams) { const signinPageUrl = `${baseUrl}${basePath}/signin` - const errors = { + const errors: Record = { default: { statusCode: 200, heading: "Error", @@ -66,7 +78,7 @@ export default function Error({ baseUrl, basePath, error = "default", res }) { } const { statusCode, heading, message, signin } = - errors[error.toLowerCase()] ?? errors.default + errors[error?.toLowerCase()] ?? errors.default res.status(statusCode) diff --git a/src/server/pages/signin.tsx b/src/server/pages/signin.tsx index 994e78653c..1cbf55becd 100644 --- a/src/server/pages/signin.tsx +++ b/src/server/pages/signin.tsx @@ -1,10 +1,20 @@ +import { InternalProvider } from "src/lib/types" + +export interface SignInServerPageParams { + csrfToken: string + providers: InternalProvider[] + callbackUrl: string + email: string + error: string +} + export default function Signin({ csrfToken, providers, callbackUrl, email, error: errorType, -}) { +}: SignInServerPageParams) { // We only want to render providers const providersToRender = providers.filter((provider) => { if (provider.type === "oauth" || provider.type === "email") { @@ -18,7 +28,7 @@ export default function Signin({ return false }) - const errors = { + const errors: Record = { Signin: "Try signing in with a different account.", OAuthSignin: "Try signing in with a different account.", OAuthCallback: "Try signing in with a different account.", diff --git a/src/server/pages/types.ts b/src/server/pages/types.ts new file mode 100644 index 0000000000..5e709397dd --- /dev/null +++ b/src/server/pages/types.ts @@ -0,0 +1,13 @@ +import { NextAuthResponse } from "src/lib/types"; + + + + + +export interface SignInServerPageParams extends BaseServerPageParams { + csrfToken: string + providers, + callbackUrl, + email, + error: errorType +} \ No newline at end of file diff --git a/src/server/pages/verify-request.tsx b/src/server/pages/verify-request.tsx index e1dc1062fb..7ed0009fee 100644 --- a/src/server/pages/verify-request.tsx +++ b/src/server/pages/verify-request.tsx @@ -1,4 +1,8 @@ -export default function VerifyRequest({ baseUrl }) { +export interface VerifyRequestServerPageParams { + baseUrl: string +} + +export default function VerifyRequest({ baseUrl }: VerifyRequestServerPageParams) { return (

Check your email

diff --git a/tsconfig.json b/tsconfig.json index 5570324f76..4fc0634f09 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,7 @@ "target": "es2019", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, - "strict": false, + "strict": true, "forceConsistentCasingInFileNames": true, "esModuleInterop": true, "module": "esnext", From bf6600235de4a8bb740d892121d437267bdace2c Mon Sep 17 00:00:00 2001 From: Thisen Date: Mon, 20 Sep 2021 19:23:53 +0200 Subject: [PATCH 02/10] wip types --- src/lib/logger.ts | 22 +++++++++++++++------- src/lib/merge.ts | 2 +- src/providers/credentials.ts | 2 +- src/server/pages/signout.tsx | 8 +++++++- src/server/pages/types.ts | 13 ------------- 5 files changed, 24 insertions(+), 23 deletions(-) delete mode 100644 src/server/pages/types.ts diff --git a/src/lib/logger.ts b/src/lib/logger.ts index bc54dafbc0..5cae369560 100644 --- a/src/lib/logger.ts +++ b/src/lib/logger.ts @@ -1,23 +1,31 @@ import { UnknownError } from "../server/errors" /** Makes sure that error is always serializable */ -function formatError(o) { +function formatError( + o: Error | UnknownError | { error: Error; [key: string]: unknown } +): { error?: Error; [key: string]: unknown } { if (o instanceof Error && !(o instanceof UnknownError)) { return { message: o.message, stack: o.stack, name: o.name } } - if (o?.error) { + if (hasErrorProperty(o)) { o.error = formatError(o.error) o.message = o.message ?? o.error.message } return o } +function hasErrorProperty( + x: unknown +): x is { error: Error; [key: string]: unknown } { + return (x as any)?.error !== "undefined" +} + /** * Override any of the methods, and the rest will use the default logger. * * [Documentation](https://next-auth.js.org/configuration/options#logger) */ -export interface LoggerInstance { +export interface LoggerInstance extends Record { warn: ( code: | "JWT_AUTO_GENERATED_SIGNING_KEY" @@ -80,15 +88,15 @@ export function proxyLogger( return logger } - const clientLogger = {} + const clientLogger: Record = {} for (const level in logger) { - clientLogger[level] = (code, metadata) => { + clientLogger[level] = (code: string, metadata: Error) => { _logger[level](code, metadata) // Logs to console if (level === "error") { metadata = formatError(metadata) } - metadata.client = true + ;(metadata as any).client = true const url = `${basePath}/_log` const body = new URLSearchParams({ level, code, ...metadata }) if (navigator.sendBeacon) { @@ -97,7 +105,7 @@ export function proxyLogger( return fetch(url, { method: "POST", body, keepalive: true }) } } - return clientLogger as LoggerInstance + return clientLogger as unknown as LoggerInstance } catch { return _logger } diff --git a/src/lib/merge.ts b/src/lib/merge.ts index 965a850785..ad75850177 100644 --- a/src/lib/merge.ts +++ b/src/lib/merge.ts @@ -6,7 +6,7 @@ function isObject(item: any): boolean { } /** Deep merge two objects */ -export function merge(target: any, ...sources: any[]) { +export function merge(target: any, ...sources: any[]): any { if (!sources.length) return target const source = sources.shift() diff --git a/src/providers/credentials.ts b/src/providers/credentials.ts index 9b4660f4d4..3f2c0296b1 100644 --- a/src/providers/credentials.ts +++ b/src/providers/credentials.ts @@ -10,7 +10,7 @@ export interface CredentialInput { } export interface CredentialsConfig< - C extends Record = {} + C extends Record = Record > extends CommonProviderOptions { type: "credentials" credentials: C diff --git a/src/server/pages/signout.tsx b/src/server/pages/signout.tsx index 98d110036e..5661d8bae3 100644 --- a/src/server/pages/signout.tsx +++ b/src/server/pages/signout.tsx @@ -1,4 +1,10 @@ -export default function Signout({ baseUrl, basePath, csrfToken }) { +export interface SignOutServerPageParams { + csrfToken: string + baseUrl: string + basePath: string +} + +export default function Signout({ baseUrl, basePath, csrfToken }: SignOutServerPageParams) { return (

Are you sure you want to sign out?

diff --git a/src/server/pages/types.ts b/src/server/pages/types.ts deleted file mode 100644 index 5e709397dd..0000000000 --- a/src/server/pages/types.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { NextAuthResponse } from "src/lib/types"; - - - - - -export interface SignInServerPageParams extends BaseServerPageParams { - csrfToken: string - providers, - callbackUrl, - email, - error: errorType -} \ No newline at end of file From bb58f5a57e0d16fe85f5555a69ead94a180d230e Mon Sep 17 00:00:00 2001 From: Thisen Date: Tue, 21 Sep 2021 20:36:31 +0200 Subject: [PATCH 03/10] wip strict types --- src/jwt/index.ts | 8 ++++--- src/lib/logger.ts | 11 ++++----- src/server/lib/cookie.ts | 39 +++++++++++++++++++------------- src/server/lib/email/signin.ts | 2 +- src/server/lib/extend-res.ts | 10 +++++--- src/server/lib/oauth/callback.ts | 17 ++++++++------ src/server/lib/utils.ts | 2 +- src/server/pages/index.ts | 11 ++++++--- src/server/pages/signin.tsx | 8 +++---- 9 files changed, 64 insertions(+), 44 deletions(-) diff --git a/src/jwt/index.ts b/src/jwt/index.ts index c38269cabd..009e5bee8a 100644 --- a/src/jwt/index.ts +++ b/src/jwt/index.ts @@ -123,12 +123,14 @@ export async function getToken( !process.env.NEXTAUTH_URL || process.env.NEXTAUTH_URL.startsWith("http://") ), - cookieName = secureCookie - ? "__Secure-next-auth.session-token" - : "next-auth.session-token", + cookieName: baseCookieName, raw = false, decode: _decode = decode, } = params ?? {} + const cookieName = + baseCookieName ?? secureCookie + ? "__Secure-next-auth.session-token" + : "next-auth.session-token" if (!req) throw new Error("Must pass `req` to JWT getToken()") // Try to get token from cookie diff --git a/src/lib/logger.ts b/src/lib/logger.ts index 5cae369560..daba495b45 100644 --- a/src/lib/logger.ts +++ b/src/lib/logger.ts @@ -1,14 +1,13 @@ import { UnknownError } from "../server/errors" +// TODO: better typing /** Makes sure that error is always serializable */ -function formatError( - o: Error | UnknownError | { error: Error; [key: string]: unknown } -): { error?: Error; [key: string]: unknown } { +function formatError(o: unknown): unknown { if (o instanceof Error && !(o instanceof UnknownError)) { return { message: o.message, stack: o.stack, name: o.name } } if (hasErrorProperty(o)) { - o.error = formatError(o.error) + o.error = formatError(o.error) as Error o.message = o.message ?? o.error.message } return o @@ -46,7 +45,7 @@ export interface LoggerInstance extends Record { const _logger: LoggerInstance = { error(code, metadata) { - metadata = formatError(metadata) + metadata = formatError(metadata) as Error console.error( `[next-auth][error][${code}]`, `\nhttps://next-auth.js.org/errors#${code.toLowerCase()}`, @@ -94,7 +93,7 @@ export function proxyLogger( _logger[level](code, metadata) // Logs to console if (level === "error") { - metadata = formatError(metadata) + metadata = formatError(metadata) as Error } ;(metadata as any).client = true const url = `${basePath}/_log` diff --git a/src/server/lib/cookie.ts b/src/server/lib/cookie.ts index 2e0a7543ef..5c27f8f662 100644 --- a/src/server/lib/cookie.ts +++ b/src/server/lib/cookie.ts @@ -1,10 +1,16 @@ // REVIEW: Is there any way to defer two types of strings? - import { CookiesOptions } from "../.." +import type { NextAuthResponse } from "../../lib/types" +import type { CookieOption } from "../types" /** Stringified form of `JWT`. Extract the content with `jwt.decode` */ export type JWTString = string +export type SetCookieOptions = Partial & { + expires?: Date | string + encode?: (val: unknown) => string +} + /** If `options.session.jwt` is set to `true`, this is a stringified `JWT`. In case of a database persisted session, this is the `sessionToken` of the session in the database.. */ export type SessionToken = T extends "jwt" ? JWTString @@ -21,13 +27,10 @@ export type SessionToken = T extends "jwt" * (with fixes for specific issues) to keep dependancy size down. */ export function set( - res, - name, - value, - options: { - expires?: Date - maxAge?: number - } = {} + res: NextAuthResponse, + name: string, + value: unknown, + options: SetCookieOptions = {} ) { const stringValue = typeof value === "object" ? "j:" + JSON.stringify(value) : String(value) @@ -38,20 +41,24 @@ export function set( } // Preserve any existing cookies that have already been set in the same session - let setCookieHeader = res.getHeader("Set-Cookie") || [] + let setCookieHeader = res.getHeader("Set-Cookie") ?? [] // If not an array (i.e. a string with a single cookie) convert it into an array if (!Array.isArray(setCookieHeader)) { - setCookieHeader = [setCookieHeader] + setCookieHeader = [setCookieHeader.toString()] } setCookieHeader.push(_serialize(name, String(stringValue), options)) res.setHeader("Set-Cookie", setCookieHeader) } -function _serialize(name, val, options) { +function _serialize( + name: string, + val: unknown, + options: SetCookieOptions = {} +) { const fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/ // eslint-disable-line no-control-regex const opt = options || {} - const enc = opt.encode || encodeURIComponent + const enc = opt.encode ?? encodeURIComponent if (typeof enc !== "function") { throw new TypeError("option encode is invalid") @@ -61,7 +68,7 @@ function _serialize(name, val, options) { throw new TypeError("argument name is invalid") } - const value = enc(val) + const value = enc(val as string) if (value && !fieldContentRegExp.test(value)) { throw new TypeError("argument val is invalid") @@ -99,8 +106,8 @@ function _serialize(name, val, options) { if (opt.expires) { let expires = opt.expires - if (typeof opt.expires.toUTCString === "function") { - expires = opt.expires.toUTCString() + if (typeof (opt.expires as Date).toUTCString === "function") { + expires = (opt.expires as Date).toUTCString() } else { const dateExpires = new Date(opt.expires) expires = dateExpires.toUTCString() @@ -153,7 +160,7 @@ function _serialize(name, val, options) { * * @TODO Review cookie settings (names, options) */ -export function defaultCookies(useSecureCookies): CookiesOptions { +export function defaultCookies(useSecureCookies: boolean): CookiesOptions { const cookiePrefix = useSecureCookies ? "__Secure-" : "" return { // default cookie options diff --git a/src/server/lib/email/signin.ts b/src/server/lib/email/signin.ts index 470fb41520..f2714d4231 100644 --- a/src/server/lib/email/signin.ts +++ b/src/server/lib/email/signin.ts @@ -48,7 +48,7 @@ export default async function email( logger.error("SEND_VERIFICATION_EMAIL_ERROR", { identifier, url, - error, + error: error as Error, }) throw new Error("SEND_VERIFICATION_EMAIL_ERROR") } diff --git a/src/server/lib/extend-res.ts b/src/server/lib/extend-res.ts index 329d2acc39..11261ff66c 100644 --- a/src/server/lib/extend-res.ts +++ b/src/server/lib/extend-res.ts @@ -1,13 +1,17 @@ +import type { NextAuthRequest, NextAuthResponse } from "src/lib/types" + /** * If the request expects a return URL, send it as a JSON response * instead of doing an actual redirect. */ -export default function extendRes(req, res) { +export default function extendRes(req: NextAuthRequest, res: NextAuthResponse) { res.redirect = (url) => { if (req.body?.json === "true") { - return res.json({ url }) + res.json({ url }) + return res } res.status(302).setHeader("Location", url) - return res.end() + res.end() + return res } } diff --git a/src/server/lib/oauth/callback.ts b/src/server/lib/oauth/callback.ts index 4a7124b2a6..2d44d12347 100644 --- a/src/server/lib/oauth/callback.ts +++ b/src/server/lib/oauth/callback.ts @@ -6,14 +6,14 @@ import { OAuthCallbackError } from "../../errors" import { TokenSet } from "openid-client" import { Account, LoggerInstance, Profile } from "src" import { OAuthChecks, OAuthConfig } from "src/providers" +import type { NextAuthRequest, NextAuthResponse } from "src/lib/types" export default async function oAuthCallback( - req, - res + req: NextAuthRequest, + res: NextAuthResponse ): Promise { const { logger } = req.options - /** @type {import("src/providers").OAuthConfig} */ const provider = req.options.provider const errorMessage = req.body.error ?? req.query.error @@ -27,14 +27,14 @@ export default async function oAuthCallback( throw error } - if (provider.version?.startsWith("1.")) { + if (provider.type === "oauth" && provider.version?.startsWith("1.")) { try { const client = await oAuth1Client(req.options) // Handle OAuth v1.x const { oauth_token, oauth_verifier } = req.query // @ts-expect-error const tokens: TokenSet = await client.getOAuthAccessToken( - oauth_token, + oauth_token as string, // @ts-expect-error null, oauth_verifier @@ -52,7 +52,7 @@ export default async function oAuthCallback( return await getProfile({ profile, tokens, provider, logger }) } catch (error) { - logger.error("OAUTH_V1_GET_ACCESS_TOKEN_ERROR", error) + logger.error("OAUTH_V1_GET_ACCESS_TOKEN_ERROR", error as Error) throw error } } @@ -159,7 +159,10 @@ async function getProfile({ // all providers, so we return an empty object; the user should then be // redirected back to the sign up page. We log the error to help developers // who might be trying to debug this when configuring a new provider. - logger.error("OAUTH_PARSE_PROFILE_ERROR", { error, OAuthProfile }) + logger.error("OAUTH_PARSE_PROFILE_ERROR", { + error: error as Error, + OAuthProfile, + }) return { profile: null, account: null, diff --git a/src/server/lib/utils.ts b/src/server/lib/utils.ts index 7cd22b78da..2fd04ce140 100644 --- a/src/server/lib/utils.ts +++ b/src/server/lib/utils.ts @@ -8,7 +8,7 @@ import { InternalOptions, InternalProvider } from "../../lib/types" * Optionally takes a second date parameter. In that case * the date in the future will be calculated from that date instead of now. */ -export function fromDate(time, date = Date.now()) { +export function fromDate(time: number, date = Date.now()) { return new Date(date + time * 1000) } diff --git a/src/server/pages/index.ts b/src/server/pages/index.ts index ceaa7dc843..afe62f818d 100644 --- a/src/server/pages/index.ts +++ b/src/server/pages/index.ts @@ -4,14 +4,19 @@ import signout from "./signout" import verifyRequest from "./verify-request" import error from "./error" import css from "../../css" +import type { VNode } from "preact" +import type { NextAuthRequest, NextAuthResponse } from "../../lib/types" /** Takes a request and response, and gives renderable pages */ -export default function renderPage(req, res) { +export default function renderPage( + req: NextAuthRequest, + res: NextAuthResponse +) { const { baseUrl, basePath, callbackUrl, csrfToken, providers, theme } = req.options res.setHeader("Content-Type", "text/html") - function send({ html, title }) { + function send({ html, title }: { html: VNode; title: string }) { res.send( `${title}
${renderToString( html @@ -44,7 +49,7 @@ export default function renderPage(req, res) { title: "Verify Request", }) }, - error(props) { + error(props?: any) { send({ html: error({ basePath, baseUrl, res, ...props }), title: "Error", diff --git a/src/server/pages/signin.tsx b/src/server/pages/signin.tsx index 1cbf55becd..2ab4ec9cc5 100644 --- a/src/server/pages/signin.tsx +++ b/src/server/pages/signin.tsx @@ -95,15 +95,15 @@ export default function Signin({
From c3701885f6f3220b8a1b334ac15c05520a5f123c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathis=20M=C3=B8ller?= Date: Fri, 1 Oct 2021 14:10:19 +0200 Subject: [PATCH 04/10] More strict typing --- src/jwt/index.ts | 15 ++++++++--- src/jwt/types.ts | 6 +++-- src/lib/client.ts | 8 +++--- src/react/index.tsx | 2 +- src/server/errors.ts | 14 +++++----- src/server/index.ts | 15 +++++++---- src/server/lib/oauth/callback.ts | 16 +++++++----- src/server/lib/oauth/client.ts | 4 +-- src/server/lib/providers.ts | 40 ++++++++++++++--------------- src/server/pages/error.tsx | 2 ++ src/server/pages/signin.tsx | 14 +++++----- src/server/pages/signout.tsx | 3 +++ src/server/pages/verify-request.tsx | 5 +++- tsconfig.json | 13 +++------- 14 files changed, 90 insertions(+), 67 deletions(-) diff --git a/src/jwt/index.ts b/src/jwt/index.ts index 009e5bee8a..ae284cdafc 100644 --- a/src/jwt/index.ts +++ b/src/jwt/index.ts @@ -2,7 +2,7 @@ import crypto from "crypto" import jose from "jose" import logger from "../lib/logger" import { NextApiRequest } from "next" -import type { JWT, JWTDecodeParams, JWTEncodeParams } from "./types" +import type { JWT, JWTDecodeParams, JWTEncodeParams, Secret } from "./types" export * from "./types" @@ -163,7 +163,14 @@ let DERIVED_SIGNING_KEY_WARNING = false let DERIVED_ENCRYPTION_KEY_WARNING = false // Do the better hkdf of Node.js one added in `v15.0.0` and Third Party one -function hkdf(secret, { byteLength, encryptionInfo, digest = "sha256" }) { +function hkdf( + secret: Secret, + { + byteLength, + encryptionInfo, + digest = "sha256", + }: { byteLength: number; encryptionInfo: string; digest?: string } +) { if (crypto.hkdfSync) { return Buffer.from( crypto.hkdfSync( @@ -182,7 +189,7 @@ function hkdf(secret, { byteLength, encryptionInfo, digest = "sha256" }) { }) } -function getDerivedSigningKey(secret) { +function getDerivedSigningKey(secret: Secret) { if (!DERIVED_SIGNING_KEY_WARNING) { logger.warn("JWT_AUTO_GENERATED_SIGNING_KEY") DERIVED_SIGNING_KEY_WARNING = true @@ -200,7 +207,7 @@ function getDerivedSigningKey(secret) { return key } -function getDerivedEncryptionKey(secret) { +function getDerivedEncryptionKey(secret: Secret) { if (!DERIVED_ENCRYPTION_KEY_WARNING) { logger.warn("JWT_AUTO_GENERATED_ENCRYPTION_KEY") DERIVED_ENCRYPTION_KEY_WARNING = true diff --git a/src/jwt/types.ts b/src/jwt/types.ts index c9a57f122d..63564c6b8a 100644 --- a/src/jwt/types.ts +++ b/src/jwt/types.ts @@ -18,7 +18,7 @@ export interface JWT extends Record, DefaultJWT {} export interface JWTEncodeParams { token?: JWT maxAge?: number - secret: string | Buffer + secret: Secret signingKey?: string signingOptions?: JoseJWT.SignOptions encryptionKey?: string @@ -29,7 +29,7 @@ export interface JWTEncodeParams { export interface JWTDecodeParams { token?: string maxAge?: number - secret: string | Buffer + secret: Secret signingKey?: string verificationKey?: string verificationOptions?: JoseJWT.VerifyOptions @@ -49,3 +49,5 @@ export interface JWTOptions { decode: typeof decode verificationOptions?: JoseJWT.VerifyOptions } + +export type Secret = string | Buffer diff --git a/src/lib/client.ts b/src/lib/client.ts index f11411da9e..e86dab55b8 100644 --- a/src/lib/client.ts +++ b/src/lib/client.ts @@ -45,7 +45,7 @@ export async function fetchData( return Object.keys(data).length > 0 ? data : null // Return null if data empty } catch (error) { logger.error("CLIENT_FETCH_ERROR", { - error, + error: error as Error, path, ...(req ? { header: req.headers } : {}), }) @@ -84,9 +84,9 @@ export function BroadcastChannel(name = "nextauth.message") { return { /** Get notified by other tabs/windows. */ receive(onReceive: (message: BroadcastMessage) => void) { - const handler = (event) => { + const handler = (event: StorageEvent) => { if (event.key !== name) return - const message: BroadcastMessage = JSON.parse(event.newValue) + const message: BroadcastMessage = JSON.parse(event.newValue ?? "") if (message?.event !== "session" || !message?.data) return onReceive(message) @@ -95,7 +95,7 @@ export function BroadcastChannel(name = "nextauth.message") { return () => window.removeEventListener("storage", handler) }, /** Notify other tabs/windows. */ - post(message) { + post(message: Record) { if (typeof window === "undefined") return localStorage.setItem( name, diff --git a/src/react/index.tsx b/src/react/index.tsx index b6fe0ed72f..f83a4e4928 100644 --- a/src/react/index.tsx +++ b/src/react/index.tsx @@ -352,7 +352,7 @@ export function SessionProvider(props: SessionProviderProps) { __NEXTAUTH._session = await getSession() setSession(__NEXTAUTH._session) } catch (error) { - logger.error("CLIENT_SESSION_ERROR", error) + logger.error("CLIENT_SESSION_ERROR", error as Error) } finally { setLoading(false) } diff --git a/src/server/errors.ts b/src/server/errors.ts index 76e0f56fb5..ebcddf3237 100644 --- a/src/server/errors.ts +++ b/src/server/errors.ts @@ -6,9 +6,9 @@ import { Adapter } from "../adapters" * @source https://iaincollins.medium.com/error-handling-in-javascript-a6172ccdf9af */ export class UnknownError extends Error { - constructor(error) { + constructor(error: Error | string) { // Support passing error or string - super(error?.message ?? error) + super((error as Error)?.message ?? error) this.name = "UnknownError" if (error instanceof Error) { this.stack = error.stack @@ -56,10 +56,10 @@ export function eventsErrorHandler( return Object.keys(methods).reduce((acc, name) => { acc[name] = async (...args: any[]) => { try { - const method: Method = methods[name] + const method: Method = methods[name as keyof Method] return await method(...args) } catch (e) { - logger.error(`${upperSnake(name)}_EVENT_ERROR`, e) + logger.error(`${upperSnake(name)}_EVENT_ERROR`, e as Error) } } return acc @@ -77,11 +77,11 @@ export function adapterErrorHandler( acc[name] = async (...args: any[]) => { try { logger.debug(`adapter_${name}`, { args }) - const method: Method = adapter[name as any] + const method: Method = adapter[name as keyof Method] return await method(...args) } catch (error) { - logger.error(`adapter_error_${name}`, error) - const e = new UnknownError(error) + logger.error(`adapter_error_${name}`, error as Error) + const e = new UnknownError(error as Error) e.name = `${capitalize(name)}Error` throw e } diff --git a/src/server/index.ts b/src/server/index.ts index 4170bc8a74..d6fbfb4e47 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -236,7 +236,7 @@ async function NextAuthHandler( logger[level](code, metadata) } catch (error) { // If logging itself failed... - logger.error("LOGGER_ERROR", error) + logger.error("LOGGER_ERROR", error as Error) } } return res.end() @@ -254,12 +254,17 @@ function NextAuth( res: NextApiResponse, options: NextAuthOptions ): any -/** Tha main entry point to next-auth */ -function NextAuth(...args) { +/** The main entry point to next-auth */ +function NextAuth( + ...args: + | [NextAuthOptions] + | [NextApiRequest, NextApiResponse, NextAuthOptions] +) { if (args.length === 1) { - return async (req, res) => await NextAuthHandler(req, res, args[0]) + return async (req: NextAuthRequest, res: NextAuthResponse) => + await NextAuthHandler(req, res, args[0]) } - return NextAuthHandler(args[0], args[1], args[2]) + return NextAuthHandler(args[0] as NextAuthRequest, args[1], args[2]) } export default NextAuth diff --git a/src/server/lib/oauth/callback.ts b/src/server/lib/oauth/callback.ts index b406ae50cc..7c626ab613 100644 --- a/src/server/lib/oauth/callback.ts +++ b/src/server/lib/oauth/callback.ts @@ -6,7 +6,11 @@ import { OAuthCallbackError } from "../../errors" import { TokenSet } from "openid-client" import { Account, LoggerInstance, Profile } from "src" import { OAuthChecks, OAuthConfig } from "src/providers" -import type { NextAuthRequest, NextAuthResponse } from "src/lib/types" +import type { + InternalProvider, + NextAuthRequest, + NextAuthResponse, +} from "src/lib/types" export default async function oAuthCallback( req: NextAuthRequest, @@ -14,7 +18,7 @@ export default async function oAuthCallback( ): Promise { const { logger } = req.options - const provider = req.options.provider + const provider = req.options.provider as InternalProvider<"oauth"> const errorMessage = req.body.error ?? req.query.error if (errorMessage) { @@ -28,7 +32,7 @@ export default async function oAuthCallback( throw error } - if (provider.type === "oauth" && provider.version?.startsWith("1.")) { + if (provider.version?.startsWith("1.")) { try { const client = await oAuth1Client(req.options) // Handle OAuth v1.x @@ -42,7 +46,7 @@ export default async function oAuthCallback( ) // @ts-expect-error let profile: Profile = await client.get( - provider.profileUrl, + (provider as any).profileUrl, tokens.oauth_token, tokens.oauth_token_secret ) @@ -110,8 +114,8 @@ export default async function oAuthCallback( return await getProfile({ profile, provider, tokens, logger }) } catch (error) { - logger.error("OAUTH_CALLBACK_ERROR", { error, providerId: provider.id }) - throw new OAuthCallbackError(error) + logger.error("OAUTH_CALLBACK_ERROR", { error: error as Error, providerId: provider.id }) + throw new OAuthCallbackError(error as Error) } } diff --git a/src/server/lib/oauth/client.ts b/src/server/lib/oauth/client.ts index d343fda2bb..4c35d17e90 100644 --- a/src/server/lib/oauth/client.ts +++ b/src/server/lib/oauth/client.ts @@ -25,8 +25,8 @@ export async function openidClient(options: InternalOptions<"oauth">) { const client = new issuer.Client( { - client_id: provider.clientId, - client_secret: provider.clientSecret, + client_id: provider.clientId as string, + client_secret: provider.clientSecret as string, redirect_uris: [provider.callbackUrl], ...provider.client, }, diff --git a/src/server/lib/providers.ts b/src/server/lib/providers.ts index e6ae497d1a..a697bb6bc4 100644 --- a/src/server/lib/providers.ts +++ b/src/server/lib/providers.ts @@ -1,5 +1,5 @@ import { InternalProvider } from "src/lib/types" -import { Provider } from "../../providers" +import { Provider, OAuthConfig } from "../../providers" import { merge } from "../../lib/merge" /** @@ -35,25 +35,25 @@ export default function parseProviders(params: { function normalizeProvider(provider?: Provider) { if (!provider) return - const normalizedProvider: any = Object.entries(provider).reduce( - (acc, [key, value]) => { - if ( - ["authorization", "token", "userinfo"].includes(key) && - typeof value === "string" - ) { - const url = new URL(value) - acc[key] = { - url: `${url.origin}${url.pathname}`, - params: Object.fromEntries(url.searchParams ?? []), - } - } else { - acc[key] = value + const normalizedProvider: InternalProvider = Object.entries( + provider + ).reduce((acc, [key, value]) => { + if ( + ["authorization", "token", "userinfo"].includes(key) && + typeof value === "string" + ) { + const url = new URL(value) + ;(acc as any)[key] = { + url: `${url.origin}${url.pathname}`, + params: Object.fromEntries(url.searchParams ?? []), } + } else { + acc[key as keyof InternalProvider] = value + } - return acc - }, - {} - ) + return acc + // eslint-disable-next-line @typescript-eslint/prefer-reduce-type-parameter, @typescript-eslint/consistent-type-assertions + }, {} as InternalProvider) // Checks only work on OAuth 2.x + OIDC providers if ( @@ -61,7 +61,7 @@ function normalizeProvider(provider?: Provider) { !provider.version?.startsWith("1.") && !provider.checks ) { - normalizedProvider.checks = ["state"] + ;(normalizedProvider as InternalProvider<"oauth">).checks = ["state"] } - return normalizedProvider as InternalProvider + return normalizedProvider } diff --git a/src/server/pages/error.tsx b/src/server/pages/error.tsx index 79ee52dfbe..9412fa71c5 100644 --- a/src/server/pages/error.tsx +++ b/src/server/pages/error.tsx @@ -1,10 +1,12 @@ import type { NextAuthResponse } from "src/lib/types" +import type { Theme } from "../.." export interface ErrorServerPageParams { baseUrl: string basePath: string error?: string res: NextAuthResponse + theme: Theme } interface ErrorView { diff --git a/src/server/pages/signin.tsx b/src/server/pages/signin.tsx index a2e3a95f00..defff70736 100644 --- a/src/server/pages/signin.tsx +++ b/src/server/pages/signin.tsx @@ -1,4 +1,5 @@ -import { InternalProvider } from "src/lib/types" +import type { InternalProvider } from "src/lib/types" +import type { Theme } from "../.." export interface SignInServerPageParams { csrfToken: string @@ -6,6 +7,7 @@ export interface SignInServerPageParams { callbackUrl: string email: string error: string + theme: Theme } export default function Signin({ @@ -29,7 +31,7 @@ export default function Signin({ return false }) - if (typeof document !== "undefined") { + if (typeof document !== "undefined" && theme.brandColor) { document.documentElement.style.setProperty( "--brand-color", theme.brandColor @@ -118,15 +120,15 @@ export default function Signin({ className="section-header" htmlFor={`input-${credential}-for-${provider.id}-provider`} > - {provider.credentials[credential].label || credential} + {provider.credentials[credential].label ?? credential} diff --git a/src/server/pages/signout.tsx b/src/server/pages/signout.tsx index b638f38a3e..06a1b6be4d 100644 --- a/src/server/pages/signout.tsx +++ b/src/server/pages/signout.tsx @@ -1,7 +1,10 @@ +import { Theme } from "../.." + export interface SignOutServerPageParams { csrfToken: string baseUrl: string basePath: string + theme: Theme } export default function Signout({ diff --git a/src/server/pages/verify-request.tsx b/src/server/pages/verify-request.tsx index b381e16046..1f5de09d07 100644 --- a/src/server/pages/verify-request.tsx +++ b/src/server/pages/verify-request.tsx @@ -1,5 +1,8 @@ +import { Theme } from "../.."; + export interface VerifyRequestServerPageParams { - baseUrl: string + baseUrl: string; + theme: Theme } export default function VerifyRequest({ diff --git a/tsconfig.json b/tsconfig.json index 02079cc600..0ca1656f3a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,14 +16,9 @@ "isolatedModules": true, "jsx": "react-jsx", "declaration": true, - "stripInternal": true + "stripInternal": true, + "skipLibCheck": true, + "skipDefaultLibCheck": true }, - "exclude": [ - "./*.js", - "./*.d.ts", - "app", - "**/tests", - "**/__tests__", - "config" - ] + "exclude": ["./*.js", "./*.d.ts", "app", "**/tests", "**/__tests__", "config"] } From d5e700718eda6095aaad8e4a9a6f22a82a21178e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathis=20M=C3=B8ller?= Date: Fri, 1 Oct 2021 14:52:05 +0200 Subject: [PATCH 05/10] Removing strict false Fix last types --- package.json | 1 - src/server/lib/oauth/client-legacy.ts | 8 +++++--- tsconfig.json | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 86445cd478..558a699c3d 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "lint:fix": "eslint . --fix", "version:pr": "node ./config/version-pr", "generate-providers": "node ./config/generate-providers.js", - "types": "tsc --noEmit --EmitDeclarationOnly false" }, "files": [ "lib", diff --git a/src/server/lib/oauth/client-legacy.ts b/src/server/lib/oauth/client-legacy.ts index d7776adbb5..150bd2356d 100644 --- a/src/server/lib/oauth/client-legacy.ts +++ b/src/server/lib/oauth/client-legacy.ts @@ -25,6 +25,7 @@ export function oAuth1Client(options: InternalOptions<"oauth">) { // @ts-expect-error oauth1Client.get = async (...args) => { return await new Promise((resolve, reject) => { + // @ts-expect-error originalGet(...args, (error, result) => { if (error) { return reject(error) @@ -39,12 +40,13 @@ export function oAuth1Client(options: InternalOptions<"oauth">) { oauth1Client.getOAuthAccessToken = async (...args: any[]) => { return await new Promise((resolve, reject) => { originalGetOAuth1AccessToken( + // @ts-expect-error ...args, - (error, oauth_token, oauth_token_secret) => { + (error: any, oauth_token: any, oauth_token_secret: any) => { if (error) { return reject(error) } - resolve({ oauth_token, oauth_token_secret }) + resolve({ oauth_token, oauth_token_secret } as any) } ) }) @@ -60,7 +62,7 @@ export function oAuth1Client(options: InternalOptions<"oauth">) { if (error) { return reject(error) } - resolve({ oauth_token, oauth_token_secret, params }) + resolve({ oauth_token, oauth_token_secret, params } as any) } ) }) diff --git a/tsconfig.json b/tsconfig.json index 0ca1656f3a..53e6e4d2c8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,7 @@ "target": "es2019", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, - "strict": true, + "strict": false, "forceConsistentCasingInFileNames": true, "esModuleInterop": true, "module": "esnext", From 5b7337fe6693977e62b68fbbad7e0a6b509e4fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathis=20M=C3=B8ller?= Date: Fri, 1 Oct 2021 14:52:48 +0200 Subject: [PATCH 06/10] Fix typo --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 558a699c3d..4cbade568d 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "lint": "eslint .", "lint:fix": "eslint . --fix", "version:pr": "node ./config/version-pr", - "generate-providers": "node ./config/generate-providers.js", + "generate-providers": "node ./config/generate-providers.js" }, "files": [ "lib", From fed900cc764fd2008fc48b9a88c953a2ff09fdad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathis=20M=C3=B8ller?= Date: Fri, 1 Oct 2021 14:54:10 +0200 Subject: [PATCH 07/10] Make TS happy --- src/server/lib/oauth/client-legacy.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/server/lib/oauth/client-legacy.ts b/src/server/lib/oauth/client-legacy.ts index 150bd2356d..2bc5a7ee0b 100644 --- a/src/server/lib/oauth/client-legacy.ts +++ b/src/server/lib/oauth/client-legacy.ts @@ -25,7 +25,6 @@ export function oAuth1Client(options: InternalOptions<"oauth">) { // @ts-expect-error oauth1Client.get = async (...args) => { return await new Promise((resolve, reject) => { - // @ts-expect-error originalGet(...args, (error, result) => { if (error) { return reject(error) @@ -40,7 +39,6 @@ export function oAuth1Client(options: InternalOptions<"oauth">) { oauth1Client.getOAuthAccessToken = async (...args: any[]) => { return await new Promise((resolve, reject) => { originalGetOAuth1AccessToken( - // @ts-expect-error ...args, (error: any, oauth_token: any, oauth_token_secret: any) => { if (error) { From 72480a67b5d06b716a5a9077dda4285ad5f6d549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathis=20M=C3=B8ller?= Date: Fri, 1 Oct 2021 15:09:15 +0200 Subject: [PATCH 08/10] Fix tests --- src/lib/client.ts | 2 +- src/lib/logger.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/client.ts b/src/lib/client.ts index e86dab55b8..5b29d843d3 100644 --- a/src/lib/client.ts +++ b/src/lib/client.ts @@ -86,7 +86,7 @@ export function BroadcastChannel(name = "nextauth.message") { receive(onReceive: (message: BroadcastMessage) => void) { const handler = (event: StorageEvent) => { if (event.key !== name) return - const message: BroadcastMessage = JSON.parse(event.newValue ?? "") + const message: BroadcastMessage = JSON.parse(event.newValue ?? "{}") if (message?.event !== "session" || !message?.data) return onReceive(message) diff --git a/src/lib/logger.ts b/src/lib/logger.ts index daba495b45..f5629279dc 100644 --- a/src/lib/logger.ts +++ b/src/lib/logger.ts @@ -16,7 +16,7 @@ function formatError(o: unknown): unknown { function hasErrorProperty( x: unknown ): x is { error: Error; [key: string]: unknown } { - return (x as any)?.error !== "undefined" + return !!(x as any)?.error } /** From 18da16841fa005805eccd319d1ad332c9669a329 Mon Sep 17 00:00:00 2001 From: Thisen Date: Sun, 31 Oct 2021 10:11:07 +0100 Subject: [PATCH 09/10] Fixes to types --- src/core/lib/cookie.ts | 6 ++++-- src/core/pages/error.tsx | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/core/lib/cookie.ts b/src/core/lib/cookie.ts index 7b4c955091..2b2b3ea2d5 100644 --- a/src/core/lib/cookie.ts +++ b/src/core/lib/cookie.ts @@ -1,6 +1,8 @@ // REVIEW: Is there any way to defer two types of strings? +import { NextAuthResponse } from "../../lib/types" import { CookiesOptions } from "../.." import { CookieOption } from "../types" +import { ServerResponse } from "http" /** Stringified form of `JWT`. Extract the content with `jwt.decode` */ export type JWTString = string @@ -26,7 +28,7 @@ export type SessionToken = T extends "jwt" * (with fixes for specific issues) to keep dependancy size down. */ export function set( - res: NextAuthResponse, + res: NextAuthResponse | ServerResponse, name: string, value: unknown, options: SetCookieOptions = {} @@ -104,7 +106,7 @@ function _serialize( } if (opt.expires) { - let expires = opt.expires + let expires: Date | string = opt.expires if (typeof (opt.expires as Date).toUTCString === "function") { expires = (opt.expires as Date).toUTCString() } else { diff --git a/src/core/pages/error.tsx b/src/core/pages/error.tsx index 7baecc2990..35e764bf23 100644 --- a/src/core/pages/error.tsx +++ b/src/core/pages/error.tsx @@ -7,6 +7,13 @@ export interface ErrorProps { error?: string } +interface ErrorView { + status: number + heading: string + message: JSX.Element + signin?: JSX.Element +} + /** Renders an error page. */ export default function ErrorPage(props: ErrorProps) { const { url, error = "default", theme } = props From 48ebfb97ebc6bbc5c128474fa6e0da7e204529c5 Mon Sep 17 00:00:00 2001 From: Thisen Date: Sun, 31 Oct 2021 11:36:41 +0100 Subject: [PATCH 10/10] Make files align with strict mode --- src/core/index.ts | 2 +- src/core/lib/oauth/authorization-url.ts | 2 +- src/core/lib/oauth/pkce-handler.ts | 19 +++++++++--- src/core/pages/index.ts | 2 +- src/core/pages/signin.tsx | 20 ++++++++++--- src/core/routes/callback.ts | 39 +++++++++++++++---------- src/core/routes/providers.ts | 2 +- src/core/routes/session.ts | 4 +-- src/core/routes/signin.ts | 10 +++++-- src/core/routes/signout.ts | 2 +- src/core/types.ts | 2 +- src/jwt/index.ts | 6 ++-- src/next/index.ts | 11 +++++-- 13 files changed, 81 insertions(+), 40 deletions(-) diff --git a/src/core/index.ts b/src/core/index.ts index a16de951a3..7e11efceb6 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -195,7 +195,7 @@ export async function NextAuthHandler< logger[level](code, metadata) } catch (error) { // If logging itself failed... - logger.error("LOGGER_ERROR", error) + logger.error("LOGGER_ERROR", error as Error) } } return {} diff --git a/src/core/lib/oauth/authorization-url.ts b/src/core/lib/oauth/authorization-url.ts index f4016d91d9..5eda92e170 100644 --- a/src/core/lib/oauth/authorization-url.ts +++ b/src/core/lib/oauth/authorization-url.ts @@ -67,7 +67,7 @@ export default async function getAuthorizationUrl(params: { cookies, } } catch (error) { - logger.error("GET_AUTHORIZATION_URL_ERROR", error) + logger.error("GET_AUTHORIZATION_URL_ERROR", error as Error) throw error } } diff --git a/src/core/lib/oauth/pkce-handler.ts b/src/core/lib/oauth/pkce-handler.ts index 71c0c08a6e..be93f9b7b6 100644 --- a/src/core/lib/oauth/pkce-handler.ts +++ b/src/core/lib/oauth/pkce-handler.ts @@ -1,4 +1,4 @@ -import * as cookie from "../cookie" +import { Cookie } from "../cookie" import * as jwt from "../../../jwt" import { generators } from "openid-client" import { InternalOptions } from "src/lib/types" @@ -16,7 +16,17 @@ const PKCE_MAX_AGE = 60 * 15 // 15 minutes in seconds * cookie: import("../cookie").Cookie * }> */ -export async function createPKCE(options) { + +type PKCE = Promise< + | undefined + | { + code_challenge: string + code_challenge_method: "S256" + cookie: Cookie + } +> + +export async function createPKCE(options: InternalOptions<"oauth">): PKCE { const { cookies, logger } = options /** @type {import("src/providers").OAuthConfig} */ const provider = options.provider @@ -29,6 +39,7 @@ export async function createPKCE(options) { // Encrypt code_verifier and save it to an encrypted cookie const encryptedCodeVerifier = await jwt.encode({ + // @ts-expect-error maxAge: PKCE_MAX_AGE, ...options.jwt, token: { code_verifier: codeVerifier }, @@ -68,7 +79,7 @@ export async function usePKCECodeVerifier(params: { }): Promise< | { codeVerifier?: string - cookie?: cookie.Cookie + cookie?: Cookie } | undefined > { @@ -85,7 +96,7 @@ export async function usePKCECodeVerifier(params: { }) // remove PKCE cookie after it has been used up - const cookie: cookie.Cookie = { + const cookie: Cookie = { name: cookies.pkceCodeVerifier.name, value: "", options: { diff --git a/src/core/pages/index.ts b/src/core/pages/index.ts index 909014a2a1..87047e4771 100644 --- a/src/core/pages/index.ts +++ b/src/core/pages/index.ts @@ -57,7 +57,7 @@ export default function renderPage({ title: "Verify Request", }) }, - error(props) { + error(props?: any) { return send({ ...ErrorPage({ url, theme, ...props }), title: "Error", diff --git a/src/core/pages/signin.tsx b/src/core/pages/signin.tsx index 4eed1c0598..2245317cd9 100644 --- a/src/core/pages/signin.tsx +++ b/src/core/pages/signin.tsx @@ -1,4 +1,16 @@ -export default function SigninPage(props) { +import { Theme } from "../.." +import { InternalProvider } from "../../lib/types" + +export interface SignInServerPageParams { + csrfToken: string + providers: InternalProvider[] + callbackUrl: string + email: string + error: string + theme: Theme +} + +export default function SigninPage(props: SignInServerPageParams) { const { csrfToken, providers, @@ -20,7 +32,7 @@ export default function SigninPage(props) { return false }) - if (typeof document !== "undefined") { + if (typeof document !== "undefined" && theme.brandColor) { document.documentElement.style.setProperty( "--brand-color", theme.brandColor @@ -114,9 +126,9 @@ export default function SigninPage(props) { > { return { headers: [{ key: "Content-Type", value: "application/json" }], - body: providers.reduce( + body: providers.reduce>( (acc, { id, name, type, signinUrl, callbackUrl }) => { acc[id] = { id, name, type, signinUrl, callbackUrl } return acc diff --git a/src/core/routes/session.ts b/src/core/routes/session.ts index 7aa073a654..37bc574b59 100644 --- a/src/core/routes/session.ts +++ b/src/core/routes/session.ts @@ -77,7 +77,7 @@ export default async function session( await events.session?.({ session, token }) } catch (error) { // If JWT not verifiable, make sure the cookie for it is removed and return empty object - logger.error("JWT_SESSION_ERROR", error) + logger.error("JWT_SESSION_ERROR", (error as Error)) response.cookies?.push({ name: options.cookies.sessionToken.name, @@ -160,7 +160,7 @@ export default async function session( }) } } catch (error) { - logger.error("SESSION_ERROR", error) + logger.error("SESSION_ERROR", (error as Error)) } } diff --git a/src/core/routes/signin.ts b/src/core/routes/signin.ts index 0ec1b910a3..4c5977075f 100644 --- a/src/core/routes/signin.ts +++ b/src/core/routes/signin.ts @@ -26,7 +26,7 @@ export default async function signin(params: { const response = await getAuthorizationUrl({ options, query }) return response } catch (error) { - logger.error("SIGNIN_OAUTH_ERROR", { error, provider }) + logger.error("SIGNIN_OAUTH_ERROR", { error: error as Error, provider }) return { redirect: `${url}/error?error=OAuthSignin` } } } else if (provider.type === "email") { @@ -73,13 +73,17 @@ export default async function signin(params: { return { redirect: signInCallbackResponse } } } catch (error) { - return { redirect: `${url}/error?${new URLSearchParams({ error })}}` } + return { + redirect: `${url}/error?${new URLSearchParams({ + error: error as string, + })}}`, + } } try { await emailSignin(email, options) } catch (error) { - logger.error("SIGNIN_EMAIL_ERROR", error) + logger.error("SIGNIN_EMAIL_ERROR", (error as Error)) return { redirect: `${url}/error?error=EmailSignin` } } diff --git a/src/core/routes/signout.ts b/src/core/routes/signout.ts index 51b84f9149..b9d3017a1b 100644 --- a/src/core/routes/signout.ts +++ b/src/core/routes/signout.ts @@ -34,7 +34,7 @@ export default async function signout(params: { await events.signOut?.({ session }) } catch (error) { // If error, log it but continue - logger.error("SIGNOUT_ERROR", error) + logger.error("SIGNOUT_ERROR", error as Error) } } diff --git a/src/core/types.ts b/src/core/types.ts index 2d33e9830f..79dcf9d9d0 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -345,7 +345,7 @@ export interface CookieOption { secure: boolean maxAge?: number domain?: string - expires?: Date + expires?: Date | string } } diff --git a/src/jwt/index.ts b/src/jwt/index.ts index 0eb0d43b0d..0e30147688 100644 --- a/src/jwt/index.ts +++ b/src/jwt/index.ts @@ -1,5 +1,5 @@ import { EncryptJWT, jwtDecrypt } from "jose" -import hkdf from '@panva/hkdf' +import hkdf from "@panva/hkdf" import { v4 as uuid } from "uuid" import { NextApiRequest } from "next" import type { JWT, JWTDecodeParams, JWTEncodeParams, JWTOptions } from "./types" @@ -99,9 +99,9 @@ export async function getToken( } } -async function getDerivedEncryptionKey(secret) { +async function getDerivedEncryptionKey(secret: string | Buffer) { return await hkdf( - 'sha256', + "sha256", secret, "", "NextAuth.js Generated Encryption Key", diff --git a/src/next/index.ts b/src/next/index.ts index 58df318f23..c0f44a930e 100644 --- a/src/next/index.ts +++ b/src/next/index.ts @@ -5,7 +5,7 @@ import { } from "next" import { NextAuthOptions, Session } from ".." import { NextAuthHandler } from "../core" -import { NextAuthAction } from "../lib/types" +import { NextAuthAction, NextAuthRequest, NextAuthResponse } from "../lib/types" import { set as setCookie } from "../core/lib/cookie" import logger, { setLogger } from "../lib/logger" @@ -81,9 +81,14 @@ function NextAuth( ): any /** Tha main entry point to next-auth */ -function NextAuth(...args) { +function NextAuth( + ...args: + | [NextAuthOptions] + | [NextApiRequest, NextApiResponse, NextAuthOptions] +) { if (args.length === 1) { - return async (req, res) => await NextAuthNextHandler(req, res, args[0]) + return async (req: NextAuthRequest, res: NextAuthResponse) => + await NextAuthNextHandler(req, res, args[0]) } return NextAuthNextHandler(args[0], args[1], args[2])