diff --git a/app.js b/app.js index 2d966a1..152427e 100644 --- a/app.js +++ b/app.js @@ -1,6 +1,7 @@ process.env.DEBUG = 'app*'; const express = require('express'); +const cookieParser = require('cookie-parser') const app = express(); const jwt = require('jsonwebtoken'); const Debug = require('debug'); @@ -16,150 +17,252 @@ const audience = process.env.AUDIENCE || 'https://generic-audience'; const debug = Debug('app'); -let {privateKey, certDer, thumbprint, exponent, modulus} = cert(jwksOrigin); +let { privateKey, certDer, thumbprint, exponent, modulus } = cert(jwksOrigin); + +const sessions = {} +const challenges = {} + +const corsOpts = (req, cb) => { + cb(null, { origin: req.headers.origin }) +} // Configure our small auth0-mock-server -app.options('*', cors()) - .use(cors()) - .use(bodyParser.json()) - .use(bodyParser.urlencoded({extended: true})) - .use(express.static(`${__dirname}/public`)) - .use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); +app.options('*', cors(corsOpts)) + .use(cors()) + .use(bodyParser.json()) + .use(bodyParser.urlencoded({ extended: true })) + .use(cookieParser()) + .use(express.static(`${__dirname}/public`)) + .use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); // This route can be used to generate a valid jwt-token. -app.post('/token', function (req, res) { - if (!req.body.email || !req.body.password) { - debug('Body is invalid!', req.body); - return res.status(400).send('Email or password is missing!'); - } - let date = Math.floor(Date.now() / 1000); - let accessToken = jwt.sign(Buffer.from(JSON.stringify({ - iss: jwksOrigin, - aud: [audience], - sub: 'auth0|' + req.body.email, - iat: date, - exp: date + 7200, - azp: req.body.clientId, - 'https://unbound.se/email': req.body.email - })), privateKey, { - algorithm: 'RS256', - keyid: thumbprint - }); +app.post('/oauth/token', (req, res) => { + const code = req.body.code + const session = sessions[code] - let idToken = jwt.sign(Buffer.from(JSON.stringify({ - iss: jwksOrigin, - aud: req.body.clientId, - nonce: req.body.nonce, - sub: 'auth0|' + req.body.email, - iat: date, - exp: date + 7200, - azp: req.body.clientId - })), privateKey, { - algorithm: 'RS256', - keyid: thumbprint - }); + let date = Math.floor(Date.now() / 1000); + let accessToken = jwt.sign(Buffer.from(JSON.stringify({ + iss: jwksOrigin, + aud: [audience], + sub: 'auth0|' + session.email, + iat: date, + exp: date + 7200, + azp: session.clientId, + })), privateKey, { + algorithm: 'RS256', + keyid: thumbprint + }); - debug('Signed token for ' + req.body.email); - // res.json({ token }); - res.redirect(`${req.body.redirect}?domain=${issuer}#access_token=${accessToken}&state=${req.body.state}&id_token=${idToken}&scope=openid%20profile%20email&expires_in=7200&token_type=Bearer`) + let idToken = jwt.sign(Buffer.from(JSON.stringify({ + iss: jwksOrigin, + aud: session.clientId, + nonce: session.nonce, + sub: 'auth0|' + session.email, + iat: date, + exp: date + 7200, + azp: session.clientId, + name: 'Example Person', + picture: 'https://cdn.playbuzz.com/cdn/5458360f-32ea-460e-a707-1a2d26760558/70bda687-cb84-4756-8a44-8cf735ed87b3.jpg', + 'https://unbound.se/roles': session.roles + })), privateKey, { + algorithm: 'RS256', + keyid: thumbprint + }); + + debug('Signed token for ' + session.email); + // res.json({ token }); + + res.json({ + access_token: accessToken, + id_token: idToken, + scope: 'openid%20profile%20email', + expires_in: 7200, + token_type: 'Bearer' + }) }); // This route can be used to generate a valid jwt-token. -app.get('/token/:email', function (req, res) { - if (!req.params.email) { - debug('No user was given!'); - return res.status(400).send('user is missing'); - } - const token = jwt.sign({ - user_id: 'auth0|' + req.params.email, - }, privateKey); - debug('Signed token for ' + req.params.email); - res.json({token}); +app.get('/token/:email', (req, res) => { + if (!req.params.email) { + debug('No user was given!'); + return res.status(400).send('user is missing'); + } + const token = jwt.sign({ + user_id: 'auth0|' + req.params.email, + }, privateKey); + debug('Signed token for ' + req.params.email); + res.json({ token }); }); -app.get('/authorize', function (req, res) { - let redirect = req.query.redirect_uri; - let state = req.query.state; - let nonce = req.query.nonce; - let clientId = req.query.client_id; +app.post('/code', (req, res) => { + if (!req.body.email || !req.body.password || !req.body.codeChallenge) { + debug('Body is invalid!', req.body); + return res.status(400).send('Email or password is missing!'); + } + + const code = req.body.codeChallenge + challenges[req.body.codeChallenge] = code + const state = req.body.state + let roles = [] + if (req.body.admin === 'true') { + roles = ['admin'] + } + sessions[code] = { + email: req.body.email, + password: req.body.password, + state: req.body.state, + nonce: req.body.nonce, + clientId: req.body.clientId, + codeChallenge: req.body.codeChallenge, + roles: roles + } + res.redirect(`${req.body.redirect}?domain=${issuer}&code=${code}&state=${encodeURIComponent(state)}`) +}) + +app.get('/authorize', (req, res) => { + const redirect = req.query.redirect_uri; + const state = req.query.state; + const nonce = req.query.nonce; + const clientId = req.query.client_id; + const codeChallenge = req.query.code_challenge; + const prompt = req.query.prompt; + const responseMode = req.query.response_mode; + if (prompt === 'none' && responseMode === 'web_message') { + const code = req.cookies['auth0'] + const session = sessions[code] + session.nonce = nonce + session.state = state + session.codeChallenge = codeChallenge + res.send(` + + +
+ + +`) + } else { + res.cookie('auth0', codeChallenge, { + sameSite: 'None', + secure: true, + httpOnly: true + }) res.send(` - -