mirror of
https://github.com/chenasraf/express-otp.git
synced 2026-05-17 17:48:11 +00:00
feat: add errorResponse option
This commit is contained in:
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"Middlewares",
|
||||
"otpauth",
|
||||
"qrcode",
|
||||
"totp"
|
||||
]
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## v0.2.0
|
||||
|
||||
- feat: add `errorResponse` option
|
||||
|
||||
## v0.1.1
|
||||
|
||||
- feat: add `verifyToken` and `verifyUser` functions
|
||||
|
||||
16
README.md
16
README.md
@@ -28,6 +28,7 @@ import otp from 'express-otp'
|
||||
const totp = otp({
|
||||
// Any identifier that is for your app
|
||||
issuer: 'my-issuer',
|
||||
|
||||
// This should return user information if a request contains a valid user
|
||||
// attempt (such as username or email)
|
||||
getUser: async (req) => {
|
||||
@@ -37,9 +38,19 @@ const totp = otp({
|
||||
}
|
||||
return { user: user.details, secret: user.secret, username: user.username }
|
||||
},
|
||||
|
||||
// By default, the token is fetched using `req.query.token`. You can change
|
||||
// that by providing a `getToken` option:
|
||||
getToken: (req) => req.headers['X-OTP-Token'] as string,
|
||||
|
||||
// Use this option to immediately respond with an error when a token is
|
||||
// missing/invalid. If this is omitted, the next route/middleware will fire
|
||||
// normally, but without `req.user` injected. Providing this function ends
|
||||
// the response if it's fired.
|
||||
errorResponse(req, res, next, error) {
|
||||
res.send(error.message)
|
||||
res.status(401)
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
@@ -73,8 +84,9 @@ await totp.generateSecretQR(username, secret, '/path/to/qr.png')
|
||||
### Authenticate a user
|
||||
|
||||
To lock any endpoint behind authentication, use the provided `authenticate()` middleware. If the
|
||||
user provided the token by your specified method, the user is injected into the request. If the
|
||||
`req` object contains a `user`, that means your user is authenticated!
|
||||
user provided the token by your specified method, the user is injected into the request. Otherwise,
|
||||
an error will be chained to the next middleware. You can make it respond immediately with an error
|
||||
by using `errorResponse` option.
|
||||
|
||||
Further requests will still need to be validated with a correct token. The authentication state will
|
||||
**not be saved in memory** between sessions - that is up to you to implement (if necessary).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "express-otp",
|
||||
"version": "0.1.1",
|
||||
"description": "Easy OTP auth for your express app",
|
||||
"version": "0.2.0",
|
||||
"description": "OTP auth for your nodejs/express app, as easy as it gets!",
|
||||
"main": "index.js",
|
||||
"repository": "https://github.com/chenasraf/express-otp",
|
||||
"homepage": "https://casraf.dev/express-otp",
|
||||
|
||||
@@ -17,9 +17,9 @@ async function main() {
|
||||
console.log('Done')
|
||||
}
|
||||
|
||||
async function copyFile(file: string) {
|
||||
const readme = await fs.readFile(file, 'utf-8')
|
||||
await fs.writeFile(path.join('build', file), readme)
|
||||
async function copyFile(filename: string) {
|
||||
const data = await fs.readFile(filename, 'utf-8')
|
||||
await fs.writeFile(path.join('build', filename), data)
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
35
src/error.ts
Normal file
35
src/error.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* The reason for an OTP error.
|
||||
*
|
||||
* - `no_user` - No user was found for the request.
|
||||
* - `no_token` - No token was found in the request.
|
||||
* - `invalid_token` - The token was invalid.
|
||||
*/
|
||||
export type OTPErrorReason = 'invalid_token' | 'no_token' | 'no_user'
|
||||
|
||||
/**
|
||||
* The error thrown when OTP verification fails.
|
||||
*/
|
||||
export class OTPError {
|
||||
/**
|
||||
* The reason for the error.
|
||||
* @param type The type of error.
|
||||
*/
|
||||
constructor(public type: OTPErrorReason) {}
|
||||
|
||||
/**
|
||||
* The error message.
|
||||
*/
|
||||
public get message(): string {
|
||||
switch (this.type) {
|
||||
case 'invalid_token':
|
||||
return 'Invalid token'
|
||||
case 'no_token':
|
||||
return 'No token provided'
|
||||
case 'no_user':
|
||||
return 'No user found'
|
||||
default:
|
||||
return `Unknown error: ${this.type}`
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,27 +6,36 @@ dotenv.config()
|
||||
|
||||
const app = express()
|
||||
|
||||
const sampleUser = { id: 1, username: process.env.USER_NAME!, secret: process.env.USER_SECRET! }
|
||||
const sampleUser = {
|
||||
id: 1,
|
||||
username: process.env.USER_NAME!,
|
||||
secret: process.env.USER_SECRET!,
|
||||
}
|
||||
|
||||
const totp = otp<typeof sampleUser>({
|
||||
issuer: 'my-issuer',
|
||||
getUser: (req) => {
|
||||
getUser(req) {
|
||||
const user = [sampleUser].find((x) => x.username === req.query.username)
|
||||
if (!user) {
|
||||
return undefined
|
||||
}
|
||||
return { user, secret: user.secret, username: user.username }
|
||||
},
|
||||
getToken: (req) => req.headers['X-OTP-Token'] as string,
|
||||
errorResponse(req, res, next, error) {
|
||||
res.send(error.message)
|
||||
res.status(401)
|
||||
},
|
||||
})
|
||||
|
||||
app.use('/generate', (req, res) => res.status(200).send(totp.generateNewSecret()))
|
||||
|
||||
app.use('/token/uri', async (req, res) =>
|
||||
res
|
||||
.status(200)
|
||||
.setHeader('Content-Type', 'text/plain')
|
||||
.send(await totp.generateSecretURL(sampleUser.username, sampleUser.secret)),
|
||||
.send(totp.generateSecretURL(sampleUser.username, sampleUser.secret)),
|
||||
)
|
||||
|
||||
app.use('/token/qr', async (req, res) =>
|
||||
res
|
||||
.status(200)
|
||||
@@ -38,17 +47,8 @@ app.use('/token/qr', async (req, res) =>
|
||||
),
|
||||
)
|
||||
|
||||
app.use(totp.authenticate())
|
||||
|
||||
app.use('/verify', (req, res) => {
|
||||
app.use('/verify', totp.authenticate(), (req, res) => {
|
||||
res.setHeader('Content-Type', 'text/plain')
|
||||
|
||||
if (!req.user) {
|
||||
res.send('Not logged in')
|
||||
res.status(401)
|
||||
return
|
||||
}
|
||||
|
||||
res.send('Logged in as user ' + JSON.stringify(req.user))
|
||||
res.status(200)
|
||||
})
|
||||
|
||||
222
src/index.ts
222
src/index.ts
@@ -3,165 +3,9 @@ import { encode } from 'hi-base32'
|
||||
import QR from 'qrcode'
|
||||
import _totp from 'totp-generator'
|
||||
import { NextFunction, Request, Response } from 'express'
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Express {
|
||||
export interface Request {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
user?: any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface TotpOptions {
|
||||
/** The issuer for your app (required) */
|
||||
issuer: string
|
||||
/** The time it takes for a new token to generate, in seconds. Defaults to 30 */
|
||||
period?: number | undefined
|
||||
/**
|
||||
* The desired SHA variant (SHA-1, SHA-224, SHA-256, SHA-384, SHA-512,
|
||||
* SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128, or SHAKE256).
|
||||
*/
|
||||
algorithm?:
|
||||
| 'SHA-1'
|
||||
| 'SHA-224'
|
||||
| 'SHA-256'
|
||||
| 'SHA-384'
|
||||
| 'SHA-512'
|
||||
| 'SHA3-224'
|
||||
| 'SHA3-256'
|
||||
| 'SHA3-384'
|
||||
| 'SHA3-512'
|
||||
| 'SHAKE128'
|
||||
| 'SHAKE256'
|
||||
/** Amount of token digits to use. Defaults to 6 */
|
||||
digits?: number | undefined
|
||||
/** The epoch time. Defaults to 0 (unix epoch) */
|
||||
timestamp?: number | undefined
|
||||
}
|
||||
|
||||
export interface UserData<U> {
|
||||
/** The user object that will get injected into further requests. */
|
||||
user: U
|
||||
/** The secret key of the user, used for generating a comparison key. */
|
||||
secret: string
|
||||
/** The username used for generating the token URL/QR. */
|
||||
username: string
|
||||
}
|
||||
|
||||
type PromiseOrValue<T> = T | Promise<T>
|
||||
|
||||
export interface TotpApiOptions<U> {
|
||||
/**
|
||||
* If the return value is not `undefined`, it uses this function to verify and then inject the correct user into further
|
||||
* requests in a middleware (usually before request processing).
|
||||
*
|
||||
* This is where you would decide which users this request belongs to, via whatever method you want - going into DB,
|
||||
* checking headers, etc.
|
||||
*
|
||||
* - The `user` property of the return value will be injected into further requests.
|
||||
* - The `secret` property of the return value will be used to generate a comparison key.
|
||||
* - The `username` property of the return value will be used to generate the token URL/QR.
|
||||
*
|
||||
* Returning `undefined` will cause the request to continue as normal, without any user injected.
|
||||
*
|
||||
* It is up to you to return an error in the actual request if necessary.
|
||||
*
|
||||
* @param {Request} req The request object.
|
||||
*/
|
||||
getUser(req: Request): PromiseOrValue<UserData<U> | undefined>
|
||||
|
||||
/**
|
||||
* This function should return the token from the request (e.g. from a header, or from a query parameter).
|
||||
*
|
||||
* @param {Request} req The request object.
|
||||
* @returns {string | undefined} The token from the request, or `undefined` if it doesn't exist.
|
||||
*/
|
||||
getToken?(req: Request): PromiseOrValue<string | undefined>
|
||||
}
|
||||
|
||||
export interface TotpMiddlewares<U> {
|
||||
/**
|
||||
* Middleware for authenticating a user, using their secret and the token provided in the request.
|
||||
*
|
||||
* Use `getUser` in the options to control which user gets used for comparing the token to and later injected into
|
||||
* further requests.
|
||||
*
|
||||
* Use `getToken` in the options to control how the token is fetched in the request (query, headers, etc).
|
||||
*/
|
||||
authenticate(): (req: Request, res: Response, next: () => void) => Promise<void>
|
||||
|
||||
/**
|
||||
* Function for generating a secret URL for a user from a given `secret` and `username`.
|
||||
*
|
||||
* @param {string} username The username to use for generating the URL.
|
||||
* @param {string} secret The secret to use for generating the URL.
|
||||
*
|
||||
* @returns {string} The URL for the user.
|
||||
*/
|
||||
generateSecretURL(username: string, secret: string): string
|
||||
|
||||
/**
|
||||
* Function for generating a QR code for a user from a given `secret` and `username`.
|
||||
*
|
||||
* This returns a PNG image as a data URL.
|
||||
*
|
||||
* @param {string} username The username to use for generating the URL.
|
||||
* @param {string} secret The secret to use for generating the URL.
|
||||
*
|
||||
* @returns {Promise<string>} The QR code as a data URL.
|
||||
*/
|
||||
generateSecretQR(username: string, secret: string): Promise<string>
|
||||
|
||||
/**
|
||||
* Function for generating a QR code for a user from a given `secret` and `username`.
|
||||
*
|
||||
* This writes the QR code directly to a file, which you can later use to serve to the user.
|
||||
*
|
||||
* @param {string} username The username to use for generating the URL.
|
||||
* @param {string} secret The secret to use for generating the URL.
|
||||
* @param {string} filename The path of the file to write the QR image to.
|
||||
*/
|
||||
generateSecretQR(username: string, secret: string, filename: string): Promise<void>
|
||||
|
||||
/**
|
||||
* Function for generating a QR code for a user from a given `secret` and `username`.
|
||||
*
|
||||
* - If `filename` is provided, this writes the QR code directly to that path, which you can later use to serve to the
|
||||
* user.
|
||||
* - If `filename` is omitted (or blank), this returns a PNG image as a data URL.
|
||||
*
|
||||
* @param {string} username The username to use for generating the URL.
|
||||
* @param {string} secret The secret to use for generating the URL.
|
||||
* @param {string} filename If provided, will use as path of the file to write the QR image to.
|
||||
*/
|
||||
generateSecretQR(username: string, secret: string, filename?: string): Promise<string | void>
|
||||
|
||||
/**
|
||||
* Generates a random, 32-byte secret key. You can attach this to your user object or DB however you want.
|
||||
*/
|
||||
generateNewSecret(): string
|
||||
|
||||
/**
|
||||
* Verifies a given token against a given secret. If the provided token is equal to the generated token for given
|
||||
* secret, it returns `true`. Otherwise, it returns `false`.
|
||||
*
|
||||
* @param secret The secret key of the user.
|
||||
* @param token The request token to verify against.
|
||||
*
|
||||
* @returns {boolean} `true` if the token is valid, `false` otherwise.
|
||||
*/
|
||||
verifyToken(secret: string, token: string): boolean
|
||||
|
||||
/**
|
||||
* Returns the user, only if the token is valid. Otherwise, it returns `undefined`.
|
||||
*
|
||||
* @param req The request object.
|
||||
* @returns {Promise<U | undefined>} The user, or `undefined` if the token is invalid.
|
||||
*/
|
||||
verifyUser(req: Request): Promise<U | undefined>
|
||||
}
|
||||
import { TotpApiOptions, TotpMiddlewares, TotpOptions, UserData } from './types'
|
||||
import { OTPError } from './error'
|
||||
export * from './types'
|
||||
|
||||
function generateQR(uri: string, filename?: string): Promise<string> | Promise<void> {
|
||||
if (!filename) {
|
||||
@@ -205,7 +49,8 @@ export default function totp<U>(_options: TotpOptions & TotpApiOptions<U>): Totp
|
||||
}
|
||||
|
||||
async function verifyUser(req: Request): Promise<U | undefined> {
|
||||
return _verifyUser<U>(options, req)
|
||||
const resp = await options.getUser(req)
|
||||
return _verifyUser<U>(options, req, resp)
|
||||
}
|
||||
|
||||
function verifyToken(secret: string, token: string): boolean {
|
||||
@@ -254,20 +99,25 @@ function _generateSecretURL<U>(
|
||||
username: string,
|
||||
) {
|
||||
const uri = new URL('otpauth://totp/')
|
||||
uri.searchParams.set('secret', secret)
|
||||
uri.username = options.issuer
|
||||
uri.password = username
|
||||
|
||||
uri.searchParams.set('issuer', options.issuer)
|
||||
uri.searchParams.set('account', username)
|
||||
uri.searchParams.set('secret', secret)
|
||||
|
||||
if (defaultOptions.algorithm !== options.algorithm) {
|
||||
uri.searchParams.set('algorithm', options.algorithm)
|
||||
}
|
||||
|
||||
if (defaultOptions.digits !== options.digits) {
|
||||
uri.searchParams.set('digits', options.digits.toString())
|
||||
}
|
||||
|
||||
if (defaultOptions.period !== options.period) {
|
||||
uri.searchParams.set('period', options.period.toString())
|
||||
}
|
||||
uri.searchParams.set('account', username)
|
||||
uri.username = options.issuer
|
||||
uri.password = username
|
||||
|
||||
return uri.toString()
|
||||
}
|
||||
|
||||
@@ -283,13 +133,13 @@ function _verifyToken<U>(
|
||||
async function _verifyUser<U>(
|
||||
options: Required<TotpOptions & TotpApiOptions<U>>,
|
||||
req: Request,
|
||||
userData: UserData<U> | undefined,
|
||||
): Promise<U | undefined> {
|
||||
const resp = await options.getUser(req)
|
||||
if (!resp) {
|
||||
if (!userData) {
|
||||
return
|
||||
}
|
||||
|
||||
const { user, secret } = resp
|
||||
const { user, secret } = userData
|
||||
const token = await options.getToken(req)
|
||||
|
||||
if (token) {
|
||||
@@ -308,16 +158,38 @@ async function _authenticate<U>(
|
||||
options: Required<TotpOptions & TotpApiOptions<U>>,
|
||||
) {
|
||||
const token = await options.getToken(req)
|
||||
const user = await _verifyUser(options, req)
|
||||
const resp = await options.getUser(req)
|
||||
const user = await _verifyUser(options, req, resp)
|
||||
|
||||
if (token) {
|
||||
if (!user) {
|
||||
next(Error('Unauthorized'))
|
||||
return
|
||||
}
|
||||
|
||||
req.user = user
|
||||
if (!token) {
|
||||
return respondWithError(req, res, next, new OTPError('no_token'), options)
|
||||
}
|
||||
|
||||
if (!resp?.user) {
|
||||
return respondWithError(req, res, next, new OTPError('no_user'), options)
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return respondWithError(req, res, next, new OTPError('invalid_token'), options)
|
||||
}
|
||||
|
||||
req.user = user
|
||||
next(null)
|
||||
}
|
||||
|
||||
function respondWithError<U>(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction,
|
||||
error: OTPError,
|
||||
options: TotpOptions & TotpApiOptions<U>,
|
||||
) {
|
||||
if (options.errorResponse !== undefined) {
|
||||
options.errorResponse(req, res, next, error)
|
||||
if (!res.writableEnded) {
|
||||
res.end()
|
||||
}
|
||||
return
|
||||
}
|
||||
next(error)
|
||||
}
|
||||
|
||||
171
src/types.ts
Normal file
171
src/types.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
import { NextFunction, Request, Response } from 'express'
|
||||
import { OTPError } from './error'
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace Express {
|
||||
export interface Request {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
user?: any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface TotpOptions {
|
||||
/** The issuer for your app (required) */
|
||||
issuer: string
|
||||
/** The time it takes for a new token to generate, in seconds. Defaults to 30 */
|
||||
period?: number | undefined
|
||||
/**
|
||||
* The desired SHA variant (SHA-1, SHA-224, SHA-256, SHA-384, SHA-512,
|
||||
* SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128, or SHAKE256).
|
||||
*/
|
||||
algorithm?:
|
||||
| 'SHA-1'
|
||||
| 'SHA-224'
|
||||
| 'SHA-256'
|
||||
| 'SHA-384'
|
||||
| 'SHA-512'
|
||||
| 'SHA3-224'
|
||||
| 'SHA3-256'
|
||||
| 'SHA3-384'
|
||||
| 'SHA3-512'
|
||||
| 'SHAKE128'
|
||||
| 'SHAKE256'
|
||||
/** Amount of token digits to use. Defaults to 6 */
|
||||
digits?: number | undefined
|
||||
/** The epoch time. Defaults to 0 (unix epoch) */
|
||||
timestamp?: number | undefined
|
||||
}
|
||||
|
||||
export interface UserData<U> {
|
||||
/** The user object that will get injected into further requests. */
|
||||
user: U
|
||||
/** The secret key of the user, used for generating a comparison key. */
|
||||
secret: string
|
||||
/** The username used for generating the token URL/QR. */
|
||||
username: string
|
||||
}
|
||||
|
||||
type PromiseOrValue<T> = T | Promise<T>
|
||||
|
||||
export interface TotpApiOptions<U> {
|
||||
/**
|
||||
* If the return value is not `undefined`, it uses this function to verify and then inject the correct user into further
|
||||
* requests in a middleware (usually before request processing).
|
||||
*
|
||||
* This is where you would decide which users this request belongs to, via whatever method you want - going into DB,
|
||||
* checking headers, etc.
|
||||
*
|
||||
* - The `user` property of the return value will be injected into further requests.
|
||||
* - The `secret` property of the return value will be used to generate a comparison key.
|
||||
* - The `username` property of the return value will be used to generate the token URL/QR.
|
||||
*
|
||||
* Returning `undefined` will cause the request to continue as normal, without any user injected.
|
||||
*
|
||||
* It is up to you to return an error in the actual request if necessary.
|
||||
*
|
||||
* @param {Request} req The request object.
|
||||
*/
|
||||
getUser(req: Request): PromiseOrValue<UserData<U> | undefined>
|
||||
|
||||
/**
|
||||
* This function should return the token from the request (e.g. from a header, or from a query parameter).
|
||||
*
|
||||
* @param {Request} req The request object.
|
||||
* @returns {string | undefined} The token from the request, or `undefined` if it doesn't exist.
|
||||
*/
|
||||
getToken?(req: Request): PromiseOrValue<string | undefined>
|
||||
|
||||
/**
|
||||
* If this function is provided, it will be used to respond to the user with an error when OTP verification fails.
|
||||
* The response ends after this function is called.
|
||||
*
|
||||
* @param req The request object.
|
||||
* @param res The response object.
|
||||
* @param next The next function.
|
||||
*/
|
||||
errorResponse?(req: Request, res: Response, next: NextFunction, reason: OTPError): void
|
||||
}
|
||||
|
||||
export interface TotpMiddlewares<U> {
|
||||
/**
|
||||
* Middleware for authenticating a user, using their secret and the token provided in the request.
|
||||
*
|
||||
* Use `getUser` in the options to control which user gets used for comparing the token to and later injected into
|
||||
* further requests.
|
||||
*
|
||||
* Use `getToken` in the options to control how the token is fetched in the request (query, headers, etc).
|
||||
*/
|
||||
authenticate(): (req: Request, res: Response, next: () => void) => Promise<void>
|
||||
|
||||
/**
|
||||
* Function for generating a secret URL for a user from a given `secret` and `username`.
|
||||
*
|
||||
* @param {string} username The username to use for generating the URL.
|
||||
* @param {string} secret The secret to use for generating the URL.
|
||||
*
|
||||
* @returns {string} The URL for the user.
|
||||
*/
|
||||
generateSecretURL(username: string, secret: string): string
|
||||
|
||||
/**
|
||||
* Function for generating a QR code for a user from a given `secret` and `username`.
|
||||
*
|
||||
* This returns a PNG image as a data URL.
|
||||
*
|
||||
* @param {string} username The username to use for generating the URL.
|
||||
* @param {string} secret The secret to use for generating the URL.
|
||||
*
|
||||
* @returns {Promise<string>} The QR code as a data URL.
|
||||
*/
|
||||
generateSecretQR(username: string, secret: string): Promise<string>
|
||||
|
||||
/**
|
||||
* Function for generating a QR code for a user from a given `secret` and `username`.
|
||||
*
|
||||
* This writes the QR code directly to a file, which you can later use to serve to the user.
|
||||
*
|
||||
* @param {string} username The username to use for generating the URL.
|
||||
* @param {string} secret The secret to use for generating the URL.
|
||||
* @param {string} filename The path of the file to write the QR image to.
|
||||
*/
|
||||
generateSecretQR(username: string, secret: string, filename: string): Promise<void>
|
||||
|
||||
/**
|
||||
* Function for generating a QR code for a user from a given `secret` and `username`.
|
||||
*
|
||||
* - If `filename` is provided, this writes the QR code directly to that path, which you can later use to serve to the
|
||||
* user.
|
||||
* - If `filename` is omitted (or blank), this returns a PNG image as a data URL.
|
||||
*
|
||||
* @param {string} username The username to use for generating the URL.
|
||||
* @param {string} secret The secret to use for generating the URL.
|
||||
* @param {string} filename If provided, will use as path of the file to write the QR image to.
|
||||
*/
|
||||
generateSecretQR(username: string, secret: string, filename?: string): Promise<string | void>
|
||||
|
||||
/**
|
||||
* Generates a random, 32-byte secret key. You can attach this to your user object or DB however you want.
|
||||
*/
|
||||
generateNewSecret(): string
|
||||
|
||||
/**
|
||||
* Verifies a given token against a given secret. If the provided token is equal to the generated token for given
|
||||
* secret, it returns `true`. Otherwise, it returns `false`.
|
||||
*
|
||||
* @param secret The secret key of the user.
|
||||
* @param token The request token to verify against.
|
||||
*
|
||||
* @returns {boolean} `true` if the token is valid, `false` otherwise.
|
||||
*/
|
||||
verifyToken(secret: string, token: string): boolean
|
||||
|
||||
/**
|
||||
* Returns the user, only if the token is valid. Otherwise, it returns `undefined`.
|
||||
*
|
||||
* @param req The request object.
|
||||
* @returns {Promise<U | undefined>} The user, or `undefined` if the token is invalid.
|
||||
*/
|
||||
verifyUser(req: Request): Promise<U | undefined>
|
||||
}
|
||||
Reference in New Issue
Block a user