2023-02-11 10:05:50 +01:00
|
|
|
import { HTTPException } from '../../http-exception.ts'
|
2022-10-31 16:07:56 +01:00
|
|
|
import type { MiddlewareHandler } from '../../types.ts'
|
2022-07-02 08:09:45 +02: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-14 01:17:20 +02:00
|
|
|
}): MiddlewareHandler => {
|
2022-07-02 08:09:45 +02: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-14 01:17:20 +02:00
|
|
|
return async (c, next) => {
|
2022-07-02 08:09:45 +02:00
|
|
|
const headerToken = c.req.headers.get('Authorization')
|
|
|
|
|
|
|
|
if (!headerToken) {
|
|
|
|
// No Authorization header
|
2023-01-12 10:53:13 +01:00
|
|
|
const res = new Response('Unauthorized', {
|
2022-07-02 08:09:45 +02:00
|
|
|
status: 401,
|
|
|
|
headers: {
|
|
|
|
'WWW-Authenticate': `${options.prefix} realm="` + realm + '"',
|
|
|
|
},
|
|
|
|
})
|
2023-01-12 10:53:13 +01:00
|
|
|
throw new HTTPException(401, { res })
|
2022-07-02 08:09:45 +02:00
|
|
|
} else {
|
|
|
|
const regexp = new RegExp('^' + options.prefix + ' +(' + TOKEN_STRINGS + ') *$')
|
|
|
|
const match = regexp.exec(headerToken)
|
|
|
|
if (!match) {
|
|
|
|
// Invalid Request
|
2023-01-12 10:53:13 +01:00
|
|
|
const res = new Response('Bad Request', {
|
2022-07-02 08:09:45 +02:00
|
|
|
status: 400,
|
|
|
|
headers: {
|
|
|
|
'WWW-Authenticate': `${options.prefix} error="invalid_request"`,
|
|
|
|
},
|
|
|
|
})
|
2023-01-12 10:53:13 +01:00
|
|
|
throw new HTTPException(400, { res })
|
2022-07-02 08:09:45 +02:00
|
|
|
} else {
|
|
|
|
const equal = await timingSafeEqual(options.token, match[1], options.hashFunction)
|
|
|
|
if (!equal) {
|
|
|
|
// Invalid Token
|
2023-01-12 10:53:13 +01:00
|
|
|
const res = new Response('Unauthorized', {
|
2022-07-02 08:09:45 +02:00
|
|
|
status: 401,
|
|
|
|
headers: {
|
|
|
|
'WWW-Authenticate': `${options.prefix} error="invalid_token"`,
|
|
|
|
},
|
|
|
|
})
|
2023-01-12 10:53:13 +01:00
|
|
|
throw new HTTPException(401, { res })
|
2022-07-02 08:09:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-09-10 11:02:36 +02:00
|
|
|
await next()
|
2022-07-02 08:09:45 +02:00
|
|
|
}
|
|
|
|
}
|