fix: refactor auth flow to explicitly pass in a host (#3909)

* fix: refactor auth flow to explicitly pass in a host

* add new error handler to all SSO providers

* refactor passport error into middleware
This commit is contained in:
Nan Yu
2022-08-04 05:00:52 -04:00
committed by GitHub
parent 0a6cfe5a6a
commit 74d9409cc3
4 changed files with 38 additions and 42 deletions

View File

@@ -9,18 +9,19 @@ import {
import { getCookieDomain, parseDomain } from "@shared/utils/domains";
import env from "@server/env";
import { Team } from "@server/models";
import { AuthRedirectError, OAuthStateMismatchError } from "../errors";
import { OAuthStateMismatchError } from "../errors";
export class StateStore {
key = "state";
store = (ctx: Context, callback: StateStoreStoreCallback) => {
// token is a short lived one-time pad to prevent replay attacks
// appDomain is the domain the user originated from when attempting auth
// we expect it to be a team subdomain, custom domain, or apex domain
const token = crypto.randomBytes(8).toString("hex");
const appDomain = parseDomain(ctx.hostname);
const state = buildState(appDomain.host, token);
// We expect host to be a team subdomain, custom domain, or apex domain
// that is passed via query param from the auth provider component.
const host = ctx.query.host?.toString() || parseDomain(ctx.hostname).host;
const state = buildState(host, token);
ctx.cookies.set(this.key, state, {
httpOnly: false,
@@ -46,24 +47,7 @@ export class StateStore {
);
}
const { host, token } = parseState(state);
// Oauth callbacks are hard-coded to come to the apex domain, so we
// redirect to the original app domain before attempting authentication.
// If there is an error during auth, the user will end up on the same domain
// that they started from.
const appDomain = parseDomain(host);
if (appDomain.host !== parseDomain(ctx.hostname).host) {
const reqProtocol = ctx.protocol;
const requestHost = ctx.get("host");
const requestPath = ctx.originalUrl;
const requestUrl = `${reqProtocol}://${requestHost}${requestPath}`;
const url = new URL(requestUrl);
url.host = appDomain.host;
return callback(AuthRedirectError(``, url.toString()), false, token);
}
const { token } = parseState(state);
// Destroy the one-time pad token and ensure it matches
ctx.cookies.set(this.key, "", {
@@ -106,6 +90,7 @@ export async function getTeamFromContext(ctx: Context) {
// we use it to infer the team they intend on signing into
const state = ctx.cookies.get("state");
const host = state ? parseState(state).host : ctx.hostname;
const domain = parseDomain(host);
let team;