mirror of
https://github.com/BradNut/node-auth
synced 2025-09-08 17:40:17 +00:00
Authorizing user on login, setting refresh token and access token on login, creating the session and storing JWT with session in DB, decoding JWT from DB while updating refresh and session tokens.
This commit is contained in:
parent
ea41b550ad
commit
594cd52866
10 changed files with 431 additions and 8 deletions
12
AccessVsRefresh.txt
Normal file
12
AccessVsRefresh.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
Access Token
|
||||
|
||||
* JWT
|
||||
* Contains all of the info someone needs to be logged
|
||||
* Says this user has Access
|
||||
* Only available in current session
|
||||
|
||||
Refresh Token
|
||||
* JWT
|
||||
* Only contains session id
|
||||
* If valid, then it is used to generate new access Token
|
||||
* Used to refresh the access token
|
||||
222
package-lock.json
generated
222
package-lock.json
generated
|
|
@ -11,7 +11,9 @@
|
|||
"bcryptjs": "^2.4.3",
|
||||
"dotenv": "^8.2.0",
|
||||
"fastify": "^3.12.0",
|
||||
"fastify-cookie": "^5.1.0",
|
||||
"fastify-static": "^4.0.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"mongodb": "^3.6.4"
|
||||
}
|
||||
},
|
||||
|
|
@ -134,6 +136,11 @@
|
|||
"node": ">=0.6.19"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
|
|
@ -158,6 +165,14 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-signature": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.1.0.tgz",
|
||||
"integrity": "sha512-Alvs19Vgq07eunykd3Xy2jF0/qSNv2u7KDbAek9H5liV1UMijbqFs5cycZvv5dVsvseT/U4H8/7/w8Koh35C4A==",
|
||||
"engines": {
|
||||
"node": ">=6.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
|
|
@ -216,6 +231,14 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ecdsa-sig-formatter": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
|
|
@ -309,6 +332,16 @@
|
|||
"node": ">=10.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fastify-cookie": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fastify-cookie/-/fastify-cookie-5.1.0.tgz",
|
||||
"integrity": "sha512-AN5C/p7YVSgnW1D9fcUL10yRIN+9lcOtyps3h4/5ZsxwrHVgdNH5T77CbnIrzfAx6qz7K/8NYQCTE8cxZIJcJg==",
|
||||
"dependencies": {
|
||||
"cookie": "^0.4.0",
|
||||
"cookie-signature": "^1.1.0",
|
||||
"fastify-plugin": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fastify-error": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/fastify-error/-/fastify-error-0.3.0.tgz",
|
||||
|
|
@ -441,6 +474,54 @@
|
|||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||
},
|
||||
"node_modules/jsonwebtoken": {
|
||||
"version": "8.5.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
|
||||
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
|
||||
"dependencies": {
|
||||
"jws": "^3.2.2",
|
||||
"lodash.includes": "^4.3.0",
|
||||
"lodash.isboolean": "^3.0.3",
|
||||
"lodash.isinteger": "^4.0.4",
|
||||
"lodash.isnumber": "^3.0.3",
|
||||
"lodash.isplainobject": "^4.0.6",
|
||||
"lodash.isstring": "^4.0.1",
|
||||
"lodash.once": "^4.0.0",
|
||||
"ms": "^2.1.1",
|
||||
"semver": "^5.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4",
|
||||
"npm": ">=1.4.28"
|
||||
}
|
||||
},
|
||||
"node_modules/jsonwebtoken/node_modules/semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/jwa": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
|
||||
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
|
||||
"dependencies": {
|
||||
"buffer-equal-constant-time": "1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jws": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||
"dependencies": {
|
||||
"jwa": "^1.4.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/light-my-request": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-4.4.1.tgz",
|
||||
|
|
@ -453,6 +534,41 @@
|
|||
"set-cookie-parser": "^2.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
"integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
|
||||
},
|
||||
"node_modules/lodash.isboolean": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||
"integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
|
||||
},
|
||||
"node_modules/lodash.isinteger": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||
"integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
|
||||
},
|
||||
"node_modules/lodash.isnumber": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||
"integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
|
||||
},
|
||||
"node_modules/lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
|
||||
},
|
||||
"node_modules/lodash.isstring": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||
"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
|
||||
},
|
||||
"node_modules/lodash.once": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||
"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
|
|
@ -996,6 +1112,11 @@
|
|||
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.5.tgz",
|
||||
"integrity": "sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg=="
|
||||
},
|
||||
"buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
|
|
@ -1014,6 +1135,11 @@
|
|||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
|
||||
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
|
||||
},
|
||||
"cookie-signature": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.1.0.tgz",
|
||||
"integrity": "sha512-Alvs19Vgq07eunykd3Xy2jF0/qSNv2u7KDbAek9H5liV1UMijbqFs5cycZvv5dVsvseT/U4H8/7/w8Koh35C4A=="
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
|
|
@ -1052,6 +1178,14 @@
|
|||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
||||
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
|
||||
},
|
||||
"ecdsa-sig-formatter": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
|
|
@ -1130,6 +1264,16 @@
|
|||
"tiny-lru": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"fastify-cookie": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fastify-cookie/-/fastify-cookie-5.1.0.tgz",
|
||||
"integrity": "sha512-AN5C/p7YVSgnW1D9fcUL10yRIN+9lcOtyps3h4/5ZsxwrHVgdNH5T77CbnIrzfAx6qz7K/8NYQCTE8cxZIJcJg==",
|
||||
"requires": {
|
||||
"cookie": "^0.4.0",
|
||||
"cookie-signature": "^1.1.0",
|
||||
"fastify-plugin": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"fastify-error": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/fastify-error/-/fastify-error-0.3.0.tgz",
|
||||
|
|
@ -1244,6 +1388,49 @@
|
|||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||
},
|
||||
"jsonwebtoken": {
|
||||
"version": "8.5.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
|
||||
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
|
||||
"requires": {
|
||||
"jws": "^3.2.2",
|
||||
"lodash.includes": "^4.3.0",
|
||||
"lodash.isboolean": "^3.0.3",
|
||||
"lodash.isinteger": "^4.0.4",
|
||||
"lodash.isnumber": "^3.0.3",
|
||||
"lodash.isplainobject": "^4.0.6",
|
||||
"lodash.isstring": "^4.0.1",
|
||||
"lodash.once": "^4.0.0",
|
||||
"ms": "^2.1.1",
|
||||
"semver": "^5.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"jwa": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
|
||||
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
|
||||
"requires": {
|
||||
"buffer-equal-constant-time": "1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"jws": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||
"requires": {
|
||||
"jwa": "^1.4.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"light-my-request": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-4.4.1.tgz",
|
||||
|
|
@ -1256,6 +1443,41 @@
|
|||
"set-cookie-parser": "^2.4.1"
|
||||
}
|
||||
},
|
||||
"lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
"integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
|
||||
},
|
||||
"lodash.isboolean": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||
"integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
|
||||
},
|
||||
"lodash.isinteger": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||
"integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
|
||||
},
|
||||
"lodash.isnumber": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||
"integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
|
||||
},
|
||||
"lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
|
||||
},
|
||||
"lodash.isstring": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||
"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
|
||||
},
|
||||
"lodash.once": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||
"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@
|
|||
"bcryptjs": "^2.4.3",
|
||||
"dotenv": "^8.2.0",
|
||||
"fastify": "^3.12.0",
|
||||
"fastify-cookie": "^5.1.0",
|
||||
"fastify-static": "^4.0.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"mongodb": "^3.6.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ export async function authorizeUser(email, password) {
|
|||
const savedPassword = userData.password
|
||||
// Compare password with one in database
|
||||
const isAuthorized = await compare(password, savedPassword)
|
||||
console.log("isAuthorized", isAuthorized)
|
||||
// Return boolean of if password is correct
|
||||
return isAuthorized
|
||||
return { isAuthorized, userId: userData._id }
|
||||
}
|
||||
27
src/accounts/logUserIn.js
Normal file
27
src/accounts/logUserIn.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { createSession } from './session.js'
|
||||
import { createTokens } from './tokens.js'
|
||||
|
||||
export async function logUserIn(userId, request, reply) {
|
||||
const connectionInformation = {
|
||||
ip: request.ip,
|
||||
userAgent: request.headers['user-agent'],
|
||||
}
|
||||
// Create Session
|
||||
const sessionToken = await createSession(userId, connectionInformation)
|
||||
// Create JWT
|
||||
const { accessToken, refreshToken } = await createTokens(sessionToken, userId)
|
||||
// Set Cookie
|
||||
const now = new Date()
|
||||
// Get date, 30 days in the future
|
||||
const refreshExpires = now.setDate(now.getDate() + 30)
|
||||
reply.setCookie('refreshToken', refreshToken, {
|
||||
path: "/",
|
||||
domain: "localhost",
|
||||
httpOnly: true,
|
||||
expires: refreshExpires,
|
||||
}).setCookie('accessToken', accessToken, {
|
||||
path: "/",
|
||||
domain: "localhost",
|
||||
httpOnly: true,
|
||||
})
|
||||
}
|
||||
25
src/accounts/session.js
Normal file
25
src/accounts/session.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { randomBytes } from 'crypto'
|
||||
|
||||
export async function createSession(userId, connection) {
|
||||
try {
|
||||
// Generate a session token
|
||||
const sessionToken = randomBytes(43).toString("hex")
|
||||
// Retrieve connection information
|
||||
const { ip, userAgent } = connection
|
||||
// database insert for ession
|
||||
const { session } = await import('../session/session.js')
|
||||
await session.insertOne({
|
||||
sessionToken,
|
||||
userId,
|
||||
valid: true,
|
||||
userAgent,
|
||||
ip,
|
||||
updatedAt: new Date(),
|
||||
createdAt: new Date(),
|
||||
})
|
||||
// Return session token
|
||||
return sessionToken
|
||||
} catch (e) {
|
||||
throw new Error('Session Creation Failed')
|
||||
}
|
||||
}
|
||||
29
src/accounts/tokens.js
Normal file
29
src/accounts/tokens.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import jwt from 'jsonwebtoken'
|
||||
|
||||
const JWTSignature = process.env.JWT_SIGNATURE
|
||||
|
||||
export async function createTokens(sessionToken, userId) {
|
||||
try {
|
||||
// Create Refresh Token
|
||||
// Session Id
|
||||
const refreshToken = jwt.sign(
|
||||
{
|
||||
sessionToken
|
||||
},
|
||||
JWTSignature
|
||||
)
|
||||
// Create Access Token
|
||||
// Session Id, User Id
|
||||
const accessToken = jwt.sign(
|
||||
{
|
||||
sessionToken,
|
||||
userId,
|
||||
},
|
||||
JWTSignature
|
||||
)
|
||||
// Return Refresh Token & Access Token
|
||||
return { accessToken, refreshToken }
|
||||
} catch (e) {
|
||||
console.error('e', e)
|
||||
}
|
||||
}
|
||||
73
src/accounts/user.js
Normal file
73
src/accounts/user.js
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import mongo from 'mongodb'
|
||||
import jwt from 'jsonwebtoken'
|
||||
import { createTokens } from './tokens.js'
|
||||
|
||||
const { ObjectId } = mongo
|
||||
|
||||
const JWTSignature = process.env.JWT_SIGNATURE
|
||||
|
||||
export async function getUserFromCookies(request, reply) {
|
||||
try {
|
||||
const { user } = await import("../user/user.js")
|
||||
const { session } = await import("../session/session.js")
|
||||
// Check to make sure access token exists
|
||||
if (request?.cookies?.accessToken) {
|
||||
// If access token
|
||||
const { accessToken } = request.cookies
|
||||
// Decode access token
|
||||
const decodedAccessToken = jwt.verify(accessToken, JWTSignature)
|
||||
// Return user from record
|
||||
return user.findOne({
|
||||
_id: ObjectId(decodedAccessToken?.userId),
|
||||
})
|
||||
}
|
||||
|
||||
if (request?.cookies?.refreshToken) {
|
||||
const { refreshToken } = request.cookies
|
||||
// Decode refresh token
|
||||
const { sessionToken } = jwt.verify(refreshToken, JWTSignature)
|
||||
// Look up session
|
||||
const currentSession = await session.findOne({ sessionToken })
|
||||
// Confirm session is valid
|
||||
if (currentSession.valid) {
|
||||
// Look up current user
|
||||
const currentUser = await user.findOne({
|
||||
_id: ObjectId(currentSession.userId)
|
||||
})
|
||||
console.log('currentUser', currentUser);
|
||||
// Refresh tokens
|
||||
await refreshTokens(sessionToken, currentUser._id, reply)
|
||||
// Retrun current user
|
||||
return currentUser
|
||||
} else {
|
||||
// bad session
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
export async function refreshTokens(sessionToken, userId, reply) {
|
||||
try {
|
||||
// Create JWT
|
||||
const { accessToken, refreshToken } = await createTokens(sessionToken, userId)
|
||||
// Set Cookie
|
||||
const now = new Date()
|
||||
// Get date, 30 days in the future
|
||||
const refreshExpires = now.setDate(now.getDate() + 30)
|
||||
reply
|
||||
.setCookie('refreshToken', refreshToken, {
|
||||
path: "/",
|
||||
domain: "localhost",
|
||||
httpOnly: true,
|
||||
expires: refreshExpires,
|
||||
}).setCookie('accessToken', accessToken, {
|
||||
path: "/",
|
||||
domain: "localhost",
|
||||
httpOnly: true,
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
42
src/index.js
42
src/index.js
|
|
@ -1,11 +1,14 @@
|
|||
import './env.js'
|
||||
import { fastify } from 'fastify'
|
||||
import fastifyStatic from 'fastify-static'
|
||||
import fastifyCookie from 'fastify-cookie';
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { connectDb } from './db.js'
|
||||
import { registerUser } from './accounts/register.js'
|
||||
import { authorizeUser } from './accounts/authorize.js'
|
||||
import { logUserIn } from './accounts/logUserIn.js'
|
||||
import { getUserFromCookies } from './accounts/user.js'
|
||||
|
||||
// ESM specific "features"
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
|
|
@ -15,6 +18,10 @@ const app = fastify()
|
|||
|
||||
async function startApp() {
|
||||
try {
|
||||
app.register(fastifyCookie, {
|
||||
secret: process.env.COOKIE_SIGNATURE,
|
||||
})
|
||||
|
||||
app.register(fastifyStatic, {
|
||||
root: path.join(__dirname, "public"),
|
||||
})
|
||||
|
|
@ -34,19 +41,42 @@ async function startApp() {
|
|||
app.post('/api/authorize', {}, async (request, reply) => {
|
||||
try {
|
||||
console.log(request.body.email, request.body.password)
|
||||
const userId = await authorizeUser(
|
||||
const { isAuthorized, userId } = await authorizeUser(
|
||||
request.body.email,
|
||||
request.body.password
|
||||
)
|
||||
if (isAuthorized) {
|
||||
await logUserIn(userId, request, reply)
|
||||
reply.send({
|
||||
data: "User Logged In",
|
||||
})
|
||||
}
|
||||
reply.send({
|
||||
data: "Auth Failed",
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('e', e);
|
||||
}
|
||||
})
|
||||
// app.get("/", {}, (request, reply) => {
|
||||
// reply.send({
|
||||
// data: "hello world",
|
||||
// })
|
||||
// })
|
||||
|
||||
app.get("/test", {}, async (request, reply) => {
|
||||
try {
|
||||
// Verify user login
|
||||
const user = await getUserFromCookies(request, reply)
|
||||
// Return user email, if it exists, otherwise return unauthorized
|
||||
if (user?._id) {
|
||||
reply.send({
|
||||
data: user,
|
||||
})
|
||||
} else {
|
||||
reply.send({
|
||||
data: "User Loopup Failed"
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error(e)
|
||||
}
|
||||
})
|
||||
|
||||
await app.listen(3000);
|
||||
console.log('🚀 Server Listening at port: 3000');
|
||||
|
|
|
|||
4
src/session/session.js
Normal file
4
src/session/session.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import { client } from '../db.js'
|
||||
|
||||
export const session = client.db("test").collection("session")
|
||||
|
||||
Loading…
Reference in a new issue