Skip to content

Commit

Permalink
feat(bearer-auth): add verifyToken option (#2449)
Browse files Browse the repository at this point in the history
* feat(bearer): add `verifyToken` option

* denoify

* allow not promise
  • Loading branch information
yusukebe authored Apr 2, 2024
1 parent 274191c commit 7425ffb
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 16 deletions.
28 changes: 20 additions & 8 deletions deno_dist/middleware/bearer-auth/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
import type { Context } from '../../context.ts'
import { HTTPException } from '../../http-exception.ts'
import type { MiddlewareHandler } from '../../types.ts'
import { timingSafeEqual } from '../../utils/buffer.ts'

const TOKEN_STRINGS = '[A-Za-z0-9._~+/-]+=*'
const PREFIX = 'Bearer'

export const bearerAuth = (options: {
token: string | string[]
realm?: string
prefix?: string
hashFunction?: Function
}): MiddlewareHandler => {
if (!options.token) {
type BearerAuthOptions =
| {
token: string | string[]
realm?: string
prefix?: string
hashFunction?: Function
}
| {
realm?: string
prefix?: string
verifyToken: (token: string, c: Context) => boolean | Promise<boolean>
hashFunction?: Function
}

export const bearerAuth = (options: BearerAuthOptions): MiddlewareHandler => {
if (!('token' in options || 'verifyToken' in options)) {
throw new Error('bearer auth middleware requires options for "token"')
}
if (!options.realm) {
Expand Down Expand Up @@ -49,7 +59,9 @@ export const bearerAuth = (options: {
throw new HTTPException(400, { res })
} else {
let equal = false
if (typeof options.token === 'string') {
if ('verifyToken' in options) {
equal = await options.verifyToken(match[1], c)
} else if (typeof options.token === 'string') {
equal = await timingSafeEqual(options.token, match[1], options.hashFunction)
} else if (Array.isArray(options.token) && options.token.length > 0) {
for (const token of options.token) {
Expand Down
32 changes: 32 additions & 0 deletions src/middleware/bearer-auth/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,19 @@ describe('Bearer Auth by Middleware', () => {
handlerExecuted = true
return c.text('auths')
})

app.use(
'/auth-verify-token/*',
bearerAuth({
verifyToken: async (token, c) => {
return c.req.path === '/auth-verify-token' && token === 'dynamic-token'
},
})
)
app.get('/auth-verify-token/*', (c) => {
handlerExecuted = true
return c.text('auth-verify-token')
})
})

it('Should authorize', async () => {
Expand Down Expand Up @@ -144,4 +157,23 @@ describe('Bearer Auth by Middleware', () => {
expect(handlerExecuted).toBeTruthy()
expect(await res2.text()).toBe('auths')
})

it('Should authorize - verifyToken option', async () => {
const res = await app.request('/auth-verify-token', {
headers: { Authorization: 'Bearer dynamic-token' },
})
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(handlerExecuted).toBeTruthy()
expect(await res.text()).toBe('auth-verify-token')
})

it('Should not authorize - verifyToken option', async () => {
const res = await app.request('/auth-verify-token', {
headers: { Authorization: 'Bearer invalid-token' },
})
expect(res).not.toBeNull()
expect(handlerExecuted).toBeFalsy()
expect(res.status).toBe(401)
})
})
28 changes: 20 additions & 8 deletions src/middleware/bearer-auth/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
import type { Context } from '../../context'
import { HTTPException } from '../../http-exception'
import type { MiddlewareHandler } from '../../types'
import { timingSafeEqual } from '../../utils/buffer'

const TOKEN_STRINGS = '[A-Za-z0-9._~+/-]+=*'
const PREFIX = 'Bearer'

export const bearerAuth = (options: {
token: string | string[]
realm?: string
prefix?: string
hashFunction?: Function
}): MiddlewareHandler => {
if (!options.token) {
type BearerAuthOptions =
| {
token: string | string[]
realm?: string
prefix?: string
hashFunction?: Function
}
| {
realm?: string
prefix?: string
verifyToken: (token: string, c: Context) => boolean | Promise<boolean>
hashFunction?: Function
}

export const bearerAuth = (options: BearerAuthOptions): MiddlewareHandler => {
if (!('token' in options || 'verifyToken' in options)) {
throw new Error('bearer auth middleware requires options for "token"')
}
if (!options.realm) {
Expand Down Expand Up @@ -49,7 +59,9 @@ export const bearerAuth = (options: {
throw new HTTPException(400, { res })
} else {
let equal = false
if (typeof options.token === 'string') {
if ('verifyToken' in options) {
equal = await options.verifyToken(match[1], c)
} else if (typeof options.token === 'string') {
equal = await timingSafeEqual(options.token, match[1], options.hashFunction)
} else if (Array.isArray(options.token) && options.token.length > 0) {
for (const token of options.token) {
Expand Down

0 comments on commit 7425ffb

Please sign in to comment.