diff --git a/app/stores/AuthStore.js b/app/stores/AuthStore.js index 6761f61f..6f9625db 100644 --- a/app/stores/AuthStore.js +++ b/app/stores/AuthStore.js @@ -102,12 +102,14 @@ class AuthStore { this.user = null; this.token = null; - // remove deprecated authentication if it exists + // remove authentication token itself Cookie.remove('accessToken', { path: '/' }); - if (this.team) { + // remove session record on apex cookie + const team = this.team; + if (team) { const sessions = Cookie.getJSON('sessions') || {}; - delete sessions[this.team.subdomain || 'root']; + delete sessions[team.subdomain || 'root']; Cookie.set('sessions', sessions, { domain: stripSubdomain(window.location.hostname), @@ -129,16 +131,8 @@ class AuthStore { } this.user = data.user; this.team = data.team; - - const sessions = Cookie.getJSON('sessions') || {}; - const subdomain = window.location.hostname.split('.')[0]; - console.log({ sessions }); - const accessToken = sessions[subdomain || 'root'] - ? sessions[subdomain || 'root'].accessToken - : Cookie.get('accessToken'); - - console.log({ accessToken }); - this.token = accessToken; + this.token = Cookie.get('accessToken'); + console.log('token', this.token); if (this.token) setImmediate(() => this.fetch()); diff --git a/server/auth/index.js b/server/auth/index.js index ed416e76..87250372 100644 --- a/server/auth/index.js +++ b/server/auth/index.js @@ -3,18 +3,42 @@ import bodyParser from 'koa-bodyparser'; import Koa from 'koa'; import Router from 'koa-router'; import validation from '../middlewares/validation'; +import auth from '../middlewares/authentication'; +import addMonths from 'date-fns/add_months'; +import { Team } from '../models'; +import { stripSubdomain } from '../../shared/utils/domains'; import slack from './slack'; import google from './google'; -const auth = new Koa(); +const app = new Koa(); const router = new Router(); router.use('/', slack.routes()); router.use('/', google.routes()); -auth.use(bodyParser()); -auth.use(validation()); -auth.use(router.routes()); +router.get('/redirect', auth(), async ctx => { + const user = ctx.state.user; -export default auth; + // transfer cookie from root to subdomain specific + ctx.cookies.set('accessToken', undefined, { + httpOnly: true, + domain: stripSubdomain(ctx.request.hostname), + }); + + ctx.cookies.set('accessToken', user.getJwtToken(), { + httpOnly: false, + expires: addMonths(new Date(), 3), + }); + + const team = await Team.findById(user.teamId); + + console.log(`redirecting: ${team.url}/dashboard`); + ctx.redirect(`${team.url}/dashboard`); +}); + +app.use(bodyParser()); +app.use(validation()); +app.use(router.routes()); + +export default app; diff --git a/server/middlewares/authentication.js b/server/middlewares/authentication.js index ab68a38d..62f4a88b 100644 --- a/server/middlewares/authentication.js +++ b/server/middlewares/authentication.js @@ -4,6 +4,7 @@ import { type Context } from 'koa'; import { User, ApiKey } from '../models'; import { AuthenticationError, UserSuspendedError } from '../errors'; import addMonths from 'date-fns/add_months'; +import addMinutes from 'date-fns/add_minutes'; import { stripSubdomain } from '../../shared/utils/domains'; export default function auth(options?: { required?: boolean } = {}) { @@ -30,6 +31,8 @@ export default function auth(options?: { required?: boolean } = {}) { token = ctx.body.token; } else if (ctx.request.query.token) { token = ctx.request.query.token; + } else { + token = ctx.cookies.get('accessToken'); } if (!token && options.required !== false) { @@ -91,30 +94,53 @@ export default function auth(options?: { required?: boolean } = {}) { } ctx.signIn = (user, team, service) => { - // not awaiting the promise here so that the request is not blocked + // update the database when the user last signed in user.updateSignedIn(ctx.request.ip); - const existing = JSON.parse(ctx.cookies.get('sessions') || '{}'); const domain = stripSubdomain(ctx.request.hostname); - const sessions = JSON.stringify({ - ...existing, - [team.subdomain || 'root']: { - name: team.name, - logo: team.logo, - accessToken: user.getJwtToken(), - }, - }); + const expires = addMonths(new Date(), 3); + + // set a cookie for which service we last signed in with. This is + // only used to display a UI hint for the user for next time ctx.cookies.set('lastSignedIn', service, { httpOnly: false, expires: new Date('2100'), domain, }); - ctx.cookies.set('sessions', sessions, { - httpOnly: false, - expires: addMonths(new Date(), 3), - domain, - }); - ctx.redirect(team.url); + + // set a transfer cookie for the access token itself and redirect + // to the teams subdomain if subdomains are enabled + if (process.env.SUBDOMAINS_ENABLED && team.subdomain) { + // get any existing sessions (teams signed in) and add this team + const existing = JSON.parse(ctx.cookies.get('sessions') || '{}'); + const sessions = JSON.stringify({ + ...existing, + [team.subdomain]: { + name: team.name, + logo: team.logo, + expires, + }, + }); + ctx.cookies.set('sessions', sessions, { + httpOnly: false, + expires, + domain, + }); + + ctx.cookies.set('accessToken', user.getJwtToken(), { + httpOnly: true, + expires: addMinutes(new Date(), 1), + domain, + }); + console.log(`redirecting: ${team.url}/auth/redirect`); + ctx.redirect(`${team.url}/auth/redirect`); + } else { + ctx.cookies.set('accessToken', user.getJwtToken(), { + httpOnly: false, + expires, + }); + ctx.redirect(team.url); + } }; return next();