Files
speckle-server/packages/server/modules/auth/rest/index.js
T
2022-04-06 15:58:05 +03:00

109 lines
3.1 KiB
JavaScript

'use strict'
const debug = require('debug')
const cors = require('cors')
const sentry = require(`@/logging/sentryHelper`)
const {
getApp,
createAuthorizationCode,
createAppTokenFromAccessCode,
refreshAppToken
} = require('../services/apps')
const { validateToken, revokeTokenById } = require(`@/modules/core/services/tokens`)
const { revokeRefreshToken } = require(`@/modules/auth/services/apps`)
const { validateScopes } = require(`@/modules/shared`)
// TODO: Secure these endpoints!
module.exports = (app) => {
/*
Generates an access code for an app.
TODO: ensure same origin.
*/
app.get('/auth/accesscode', async (req, res) => {
try {
const appId = req.query.appId
const app = await getApp({ id: appId })
if (!app) throw new Error('App does not exist.')
const challenge = req.query.challenge
const userToken = req.query.token
// 1. Validate token
const { valid, scopes, userId } = await validateToken(userToken)
if (!valid) throw new Error('Invalid token')
// 2. Validate token scopes
await validateScopes(scopes, 'tokens:write')
const ac = await createAuthorizationCode({ appId, userId, challenge })
return res.redirect(`${app.redirectUrl}?access_code=${ac}`)
} catch (err) {
sentry({ err })
debug('speckle:errors')(err)
return res.status(400).send(err.message)
}
})
/*
Generates a new api token: (1) either via a valid refresh token or (2) via a valid access token
*/
app.options('/auth/token', cors())
app.post('/auth/token', cors(), async (req, res) => {
try {
// Token refresh
if (req.body.refreshToken) {
if (!req.body.appId || !req.body.appSecret)
throw new Error('Invalid request - refresh token')
const authResponse = await refreshAppToken({
refreshToken: req.body.refreshToken,
appId: req.body.appId,
appSecret: req.body.appSecret
})
return res.send(authResponse)
}
// Access-code - token exchange
if (
!req.body.appId ||
!req.body.appSecret ||
!req.body.accessCode ||
!req.body.challenge
)
throw new Error('Invalid request' + JSON.stringify(req.body))
const authResponse = await createAppTokenFromAccessCode({
appId: req.body.appId,
appSecret: req.body.appSecret,
accessCode: req.body.accessCode,
challenge: req.body.challenge
})
return res.send(authResponse)
} catch (err) {
sentry({ err })
return res.status(401).send({ err: err.message })
}
})
/*
Ensures a user is logged out by invalidating their token and refresh token.
*/
app.post('/auth/logout', async (req, res) => {
try {
const token = req.body.token
const refreshToken = req.body.refreshToken
if (!token) throw new Error('Invalid request')
await revokeTokenById(token)
if (refreshToken) await revokeRefreshToken({ tokenId: refreshToken })
return res.status(200).send({ message: 'You have logged out.' })
} catch (err) {
sentry({ err })
return res.status(400).send({ err: err.message })
}
})
}