2023-02-11 09:05:50 +00:00
|
|
|
import { HTTPException } from '../../http-exception.ts'
|
2022-10-31 15:07:56 +00:00
|
|
|
import type { MiddlewareHandler } from '../../types.ts'
|
2022-07-02 06:09:45 +00:00
|
|
|
import { timingSafeEqual } from '../../utils/buffer.ts'
|
|
|
|
|
|
|
|
const TOKEN_STRINGS = '[A-Za-z0-9._~+/-]+=*'
|
|
|
|
const PREFIX = 'Bearer'
|
|
|
|
|
|
|
|
export const bearerAuth = (options: {
|
|
|
|
token: string
|
|
|
|
realm?: string
|
|
|
|
prefix?: string
|
|
|
|
hashFunction?: Function
|
2022-09-13 23:17:20 +00:00
|
|
|
}): MiddlewareHandler => {
|
2022-07-02 06:09:45 +00:00
|
|
|
if (!options.token) {
|
|
|
|
throw new Error('bearer auth middleware requires options for "token"')
|
|
|
|
}
|
|
|
|
if (!options.realm) {
|
|
|
|
options.realm = ''
|
|
|
|
}
|
|
|
|
if (!options.prefix) {
|
|
|
|
options.prefix = PREFIX
|
|
|
|
}
|
|
|
|
|
|
|
|
const realm = options.realm?.replace(/"/g, '\\"')
|
|
|
|
|
2022-09-13 23:17:20 +00:00
|
|
|
return async (c, next) => {
|
2023-09-05 13:08:43 +00:00
|
|
|
const headerToken = c.req.header('Authorization')
|
2022-07-02 06:09:45 +00:00
|
|
|
|
|
|
|
if (!headerToken) {
|
|
|
|
// No Authorization header
|
2023-01-12 09:53:13 +00:00
|
|
|
const res = new Response('Unauthorized', {
|
2022-07-02 06:09:45 +00:00
|
|
|
status: 401,
|
|
|
|
headers: {
|
|
|
|
'WWW-Authenticate': `${options.prefix} realm="` + realm + '"',
|
|
|
|
},
|
|
|
|
})
|
2023-01-12 09:53:13 +00:00
|
|
|
throw new HTTPException(401, { res })
|
2022-07-02 06:09:45 +00:00
|
|
|
} else {
|
|
|
|
const regexp = new RegExp('^' + options.prefix + ' +(' + TOKEN_STRINGS + ') *$')
|
|
|
|
const match = regexp.exec(headerToken)
|
|
|
|
if (!match) {
|
|
|
|
// Invalid Request
|
2023-01-12 09:53:13 +00:00
|
|
|
const res = new Response('Bad Request', {
|
2022-07-02 06:09:45 +00:00
|
|
|
status: 400,
|
|
|
|
headers: {
|
|
|
|
'WWW-Authenticate': `${options.prefix} error="invalid_request"`,
|
|
|
|
},
|
|
|
|
})
|
2023-01-12 09:53:13 +00:00
|
|
|
throw new HTTPException(400, { res })
|
2022-07-02 06:09:45 +00:00
|
|
|
} else {
|
|
|
|
const equal = await timingSafeEqual(options.token, match[1], options.hashFunction)
|
|
|
|
if (!equal) {
|
|
|
|
// Invalid Token
|
2023-01-12 09:53:13 +00:00
|
|
|
const res = new Response('Unauthorized', {
|
2022-07-02 06:09:45 +00:00
|
|
|
status: 401,
|
|
|
|
headers: {
|
|
|
|
'WWW-Authenticate': `${options.prefix} error="invalid_token"`,
|
|
|
|
},
|
|
|
|
})
|
2023-01-12 09:53:13 +00:00
|
|
|
throw new HTTPException(401, { res })
|
2022-07-02 06:09:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-09-10 09:02:36 +00:00
|
|
|
await next()
|
2022-07-02 06:09:45 +00:00
|
|
|
}
|
|
|
|
}
|