dh_demo

DreamHanks demo project
git clone git://git.lair.cx/dh_demo
Log | Files | Refs | README

token.ts (2288B)


      1 import { getAccessTokenCookieName } from '@/lib/env'
      2 import { sign, verify, JwtPayload } from 'jsonwebtoken'
      3 import { NextApiRequest } from 'next'
      4 
      5 const TOKEN_ALGORITHM = 'HS256'
      6 export const TOKEN_EXPIRES_IN = 5 * 60 // 5분
      7 export const REFRESH_TOKEN_EXPIRES_IN = 30 * 24 * 60 * 60 // 30일
      8 
      9 export interface AccessTokenPayload extends JwtPayload {
     10   tid?: string
     11   uid?: number
     12 }
     13 
     14 export function getTokenSecret () {
     15   return process.env.WIKI_JWT_SECRET ?? 'dangerously_insecure_s3cr3t'
     16 }
     17 
     18 /**
     19  * JWT를 발급합니다.
     20  * @returns [accessToken, refreshToken, tokenId]
     21  */
     22 export function signToken (
     23   tid: string,
     24   uid: number,
     25 ): [string, string] {
     26   const accessToken = sign(
     27     { tid, uid },
     28     getTokenSecret(),
     29     {
     30       algorithm: TOKEN_ALGORITHM,
     31       expiresIn: TOKEN_EXPIRES_IN,
     32     },
     33   )
     34 
     35   const refreshToken = sign(
     36     {
     37       tid: tid,
     38       uid: uid,
     39       refresh: true,
     40     },
     41     getTokenSecret(),
     42     {
     43       algorithm: TOKEN_ALGORITHM,
     44       expiresIn: REFRESH_TOKEN_EXPIRES_IN,
     45     },
     46   )
     47 
     48   return [
     49     accessToken,
     50     refreshToken,
     51   ]
     52 }
     53 
     54 export async function verifyToken (token: string) {
     55   return new Promise((resolve, reject) => {
     56     verify(token, getTokenSecret(), {
     57       algorithms: [TOKEN_ALGORITHM],
     58     }, (err, decoded) => {
     59       if (err != null) {
     60         reject(err)
     61         return
     62       }
     63 
     64       resolve(decoded)
     65     })
     66   })
     67 }
     68 
     69 export async function authenticationFromCookies (cookies: NextApiRequest['cookies']) {
     70   const accessToken = cookies[getAccessTokenCookieName()]
     71   if (accessToken == null) {
     72     return null
     73   }
     74 
     75   try {
     76     const decoded = await verifyToken(accessToken)
     77     return decoded as AccessTokenPayload
     78   } catch (e) {
     79     console.log('token: failed to verify access token', e)
     80     return null
     81   }
     82 }
     83 
     84 export async function getUserIdFromAccessToken (accessToken?: string): Promise<number | null> {
     85   if (accessToken == null) {
     86     return null
     87   }
     88 
     89   const decoded = await new Promise((resolve, reject) => {
     90     verify(accessToken, getTokenSecret(), (err, decoded) => {
     91       if (err) {
     92         reject(err)
     93       } else {
     94         resolve(decoded)
     95       }
     96     })
     97   })
     98 
     99   if (typeof decoded !== 'object' || decoded == null || !('uid' in decoded)) {
    100     return null
    101   }
    102 
    103   return parseInt(decoded.uid as string, 10)
    104 }