chore: Refactor authentication pass between subdomains (#1619)

* fix: Use get request instead of cookie to transfer token between domains

* Add domain to database
Add redirects to team domain when present

* 30s -> 1m

* fix: Avoid redirect loop if subdomain and domain set

* fix: Create a transfer specific token to prevent replay requests

* refactor: Move isCustomDomain out of shared as it won't work on the client
This commit is contained in:
Tom Moor
2020-11-04 19:54:04 -08:00
committed by GitHub
parent 3d09c8f655
commit 1b6a986986
11 changed files with 136 additions and 32 deletions

View File

@ -1,5 +1,6 @@
// @flow
import crypto from "crypto";
import addMinutes from "date-fns/add_minutes";
import subMinutes from "date-fns/sub_minutes";
import JWT from "jsonwebtoken";
import uuid from "uuid";
@ -91,12 +92,12 @@ User.prototype.collectionIds = async function (options = {}) {
.map((c) => c.id);
};
User.prototype.updateActiveAt = function (ip) {
User.prototype.updateActiveAt = function (ip, force = false) {
const fiveMinutesAgo = subMinutes(new Date(), 5);
// ensure this is updated only every few minutes otherwise
// we'll be constantly writing to the DB as API requests happen
if (this.lastActiveAt < fiveMinutesAgo) {
if (this.lastActiveAt < fiveMinutesAgo || force) {
this.lastActiveAt = new Date();
this.lastActiveIp = ip;
return this.save({ hooks: false });
@ -109,17 +110,42 @@ User.prototype.updateSignedIn = function (ip) {
return this.save({ hooks: false });
};
User.prototype.getJwtToken = function () {
return JWT.sign({ id: this.id }, this.jwtSecret);
// Returns a session token that is used to make API requests and is stored
// in the client browser cookies to remain logged in.
User.prototype.getJwtToken = function (expiresAt?: Date) {
return JWT.sign(
{
id: this.id,
expiresAt: expiresAt ? expiresAt.toISOString() : undefined,
type: "session",
},
this.jwtSecret
);
};
// Returns a temporary token that is only used for transferring a session
// between subdomains or domains. It has a short expiry and can only be used once
User.prototype.getTransferToken = function () {
return JWT.sign(
{
id: this.id,
createdAt: new Date().toISOString(),
expiresAt: addMinutes(new Date(), 1).toISOString(),
type: "transfer",
},
this.jwtSecret
);
};
// Returns a temporary token that is only used for logging in from an email
// It can only be used to sign in once and has a medium length expiry
User.prototype.getEmailSigninToken = function () {
if (this.service && this.service !== "email") {
throw new Error("Cannot generate email signin token for OAuth user");
}
return JWT.sign(
{ id: this.id, createdAt: new Date().toISOString() },
{ id: this.id, createdAt: new Date().toISOString(), type: "email-signin" },
this.jwtSecret
);
};