Skip to content

Commit

Permalink
better types
Browse files Browse the repository at this point in the history
  • Loading branch information
mshick committed Mar 17, 2024
1 parent 5f8ecb7 commit 2d87102
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 137 deletions.
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,20 @@
"exports": {
".": "./dist/index.js",
"./react": "./dist/react/index.js",
"./app": "./dist/app/index.js",
"./pages": "./dist/pages/index.js"
"./v5": "./dist/v5/index.js",
"./v4": "./dist/v4/index.js"
},
"types": "./dist",
"typesVersions": {
"*": {
"react": [
"dist/react/index.d.ts"
],
"app": [
"dist/app/index.d.ts"
"v5": [
"dist/v5/index.d.ts"
],
"pages": [
"dist/pages/index.d.ts"
"v4": [
"dist/v4/index.d.ts"
]
}
},
Expand All @@ -61,8 +61,8 @@
"dist/types.js",
"dist/utils.d.ts",
"dist/utils.js",
"dist/app",
"dist/pages"
"dist/v5",
"dist/v4"
],
"scripts": {
"build": "del-cli dist && tsc -p tsconfig.build.json",
Expand Down
39 changes: 0 additions & 39 deletions src/app/index.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/callbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { createSigningFns } from './token.js'
*/
export function createSessionCallback(
signingOptions: CreateSigningFnsParameters,
nextAuthOptions: NextAuthConfig,
nextAuthOptions: Pick<NextAuthConfig, 'callbacks'>,
): CallbacksOptions['session'] {
const signAccessTokens = createSigningFns(signingOptions)

Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { createNextAuthAllAccess as default } from './pages/index.js'
export { createNextAuthAllAccess as default } from './v4/index.js'
83 changes: 33 additions & 50 deletions src/next-auth-all-access.ts
Original file line number Diff line number Diff line change
@@ -1,68 +1,51 @@
import type { NextAuthConfig } from 'next-auth'
import fs from 'node:fs'
import { createSessionCallback } from './callbacks.js'
import { importPkcs8 } from './key.js'
import type { CreateSigningFnsParameters } from './token.js'
import type { HandlerOptions, NextAuthAllAccessOptions } from './types.js'
import { isJsonWebKeySet } from './types.js'
import { getIssuer, getOrigin, sanitizeKey } from './utils.js'

/**
* Wraps NextAuth with AllAccess code, which adds AllAccess endpoints and inserts
* access tokens into the session object.
*/
export function createInitializer(handler: any) {
return (options: NextAuthAllAccessOptions) => {
const _jwks = options.jwks
const jwksPath = options.jwksPath ?? process.env['ALLACCESS_JWKS_PATH']
const privateKey = options.privateKey ?? process.env['ALLACCESS_PRIVATE_KEY']
export function createInitializerOptions(options: NextAuthAllAccessOptions) {
const _jwks = options.jwks
const jwksPath = options.jwksPath ?? process.env['ALLACCESS_JWKS_PATH']
const privateKey = options.privateKey ?? process.env['ALLACCESS_PRIVATE_KEY']

if ((!jwksPath && !_jwks) || !privateKey) {
throw new Error('JWKS file path and private key are required')
}

let jwks

if (jwksPath) {
jwks = JSON.parse(fs.readFileSync(jwksPath, 'utf-8')) as unknown
} else {
jwks = _jwks
}

if (!isJsonWebKeySet(jwks)) {
throw new Error('JWKS file is invalid')
}
if ((!jwksPath && !_jwks) || !privateKey) {
throw new Error('JWKS file path and private key are required')
}

const kid = jwks.keys[0]?.kid
let jwks

if (!kid) {
throw new Error('JWKS file is invalid')
}
if (jwksPath) {
jwks = JSON.parse(fs.readFileSync(jwksPath, 'utf-8')) as unknown
} else {
jwks = _jwks
}

const issuer = getIssuer(options.issuer)
if (!isJsonWebKeySet(jwks)) {
throw new Error('JWKS file is invalid')
}

const handlerOptions: HandlerOptions = {
issuer,
origin: getOrigin(options.origin),
jwks,
}
const kid = jwks.keys[0]?.kid

const signingOptions: CreateSigningFnsParameters = {
clients: options.clients,
privateKey: importPkcs8(sanitizeKey(privateKey)),
issuer,
kid,
}
if (!kid) {
throw new Error('JWKS file is invalid')
}

return (createNextAuth: (opt: NextAuthConfig) => any, nextAuthOptions: NextAuthConfig) => {
const sessionCallback = createSessionCallback(signingOptions, nextAuthOptions)
const issuer = getIssuer(options.issuer)

nextAuthOptions.callbacks = {
...nextAuthOptions.callbacks,
session: sessionCallback,
}
const handlerOptions: HandlerOptions = {
issuer,
origin: getOrigin(options.origin),
jwks,
}

return handler(handlerOptions, createNextAuth(nextAuthOptions))
}
const signingOptions: CreateSigningFnsParameters = {
clients: options.clients,
privateKey: importPkcs8(sanitizeKey(privateKey)),
issuer,
kid,
}

return { handlerOptions, signingOptions }
}
38 changes: 0 additions & 38 deletions src/pages/index.ts

This file was deleted.

56 changes: 56 additions & 0 deletions src/v4/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
import { NextAuthConfig } from 'next-auth'
import { createSessionCallback } from '../callbacks.js'
import jwksHandler from '../handlers/jwks.js'
import openidConfigurationHandler from '../handlers/openid-configuration.js'
import { createInitializerOptions } from '../next-auth-all-access.js'
import type { HandlerOptions, NextAuthAllAccessOptions } from '../types.js'

/**
* Wrap NextAuth returning a v4-style API handler
*/
function wrapNextAuth(options: HandlerOptions, nextAuth: NextApiHandler): NextApiHandler {
return async (req: NextApiRequest, res: NextApiResponse) => {
let {
query: { nextauth: route },
} = req

route = (Array.isArray(route) ? route : [route]).join('/')

switch (route) {
case 'all-access/jwks.json': {
const response = jwksHandler(options)
res.send(response)
return
}

case 'all-access/.well-known/openid-configuration': {
const response = openidConfigurationHandler(options)
res.send(response)
return
}

default: {
await nextAuth(req, res)
}
}
}
}

export const createNextAuthAllAccess = (options: NextAuthAllAccessOptions) => {
const { handlerOptions, signingOptions } = createInitializerOptions(options)

return (
createNextAuth: (options: Pick<NextAuthConfig, 'callbacks'>) => any,
nextAuthOptions: Pick<NextAuthConfig, 'callbacks'>,
): NextApiHandler => {
const sessionCallback = createSessionCallback(signingOptions, nextAuthOptions)

nextAuthOptions.callbacks = {
...nextAuthOptions.callbacks,
session: sessionCallback,
}

return wrapNextAuth(handlerOptions, createNextAuth(nextAuthOptions))
}
}
54 changes: 54 additions & 0 deletions src/v5/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type NextAuth from 'next-auth'
import type { NextAuthConfig, NextAuthResult } from 'next-auth'
import type { NextRequest } from 'next/server'
import { createSessionCallback } from '../callbacks.js'
import jwksHandler from '../handlers/jwks.js'
import openidConfigurationHandler from '../handlers/openid-configuration.js'
import { createInitializerOptions } from '../next-auth-all-access.js'
import type { HandlerOptions, NextAuthAllAccessOptions } from '../types.js'

/**
* Wrap NextAuth returning a v5-style `NextAuthResult`
*/
function wrapNextAuth(options: HandlerOptions, nextAuth: NextAuthResult) {
const { GET } = nextAuth.handlers

const getWrapper = async (req: NextRequest) => {
const { pathname } = req.nextUrl

if (pathname.endsWith('all-access/jwks.json')) {
const response = jwksHandler(options)
return Response.json(response)
}

if (pathname.endsWith('all-access/.well-known/openid-configuration')) {
const response = openidConfigurationHandler(options)
return Response.json(response)
}

return GET(req)
}

return {
...nextAuth,
handlers: {
...nextAuth.handlers,
GET: getWrapper,
},
}
}

export const createNextAuthAllAccess = (options: NextAuthAllAccessOptions) => {
const { handlerOptions, signingOptions } = createInitializerOptions(options)

return (createNextAuth: typeof NextAuth, nextAuthOptions: NextAuthConfig): NextAuthResult => {
const sessionCallback = createSessionCallback(signingOptions, nextAuthOptions)

nextAuthOptions.callbacks = {
...nextAuthOptions.callbacks,
session: sessionCallback,
}

return wrapNextAuth(handlerOptions, createNextAuth(nextAuthOptions))
}
}

0 comments on commit 2d87102

Please sign in to comment.