payload-auth-plugin
Version:
Authentication plugin for Payload CMS
131 lines (130 loc) • 3.83 kB
JavaScript
// src/core/protocols/oauth/oauth_authentication.ts
import * as jose from "jose";
import { APP_COOKIE_SUFFIX } from "../../../constants.js";
import {
MissingCollection,
UserNotFoundAPIError
} from "../../errors/apiErrors.js";
import {
createSessionCookies,
invalidateOAuthCookies
} from "../../utils/cookies.js";
import { v4 as uuid } from "uuid";
import { removeExpiredSessions } from "../../utils/session.js";
async function OAuthAuthentication(pluginType, collections, allowOAuthAutoSignUp, useAdmin, secret, request, successRedirectPath, errorRedirectPath, account) {
const {
email: _email,
sub,
name,
scope,
issuer,
picture,
access_token
} = account;
const { payload } = request;
const email = _email.toLowerCase();
const userRecords = await payload.find({
collection: collections.usersCollection,
where: {
email: {
equals: email
}
}
});
let userRecord;
if (userRecords.docs.length === 1) {
userRecord = userRecords.docs[0];
} else if (allowOAuthAutoSignUp) {
const data2 = {
email,
name
};
const hasAuthEnabled = Boolean(payload.collections[collections.usersCollection].config.auth);
if (hasAuthEnabled) {
data2.password = jose.base64url.encode(crypto.getRandomValues(new Uint8Array(16)));
}
const userRecords2 = await payload.create({
collection: collections.usersCollection,
data: data2
});
userRecord = userRecords2;
} else {
return new UserNotFoundAPIError;
}
const data = {
scope,
name,
picture,
issuerName: issuer,
access_token
};
const accountRecords = await payload.find({
collection: collections.accountsCollection,
where: {
sub: { equals: sub }
}
});
if (accountRecords.docs && accountRecords.docs.length === 1) {
await payload.update({
collection: collections.accountsCollection,
id: accountRecords.docs[0].id,
data
});
} else {
data.sub = sub;
data.user = userRecord.id;
await payload.create({
collection: collections.accountsCollection,
data
});
}
let cookies = [];
const collectionConfig = payload.config.collections.find((collection) => collection.slug === collections.usersCollection);
if (!collectionConfig) {
return new MissingCollection;
}
const sessionID = collectionConfig?.auth.useSessions ? uuid() : null;
if (collectionConfig?.auth.useSessions) {
const now = new Date;
const tokenExpInMs = collectionConfig.auth.tokenExpiration * 1000;
const expiresAt = new Date(now.getTime() + tokenExpInMs);
const session = { id: sessionID, createdAt: now, expiresAt };
if (!userRecord["sessions"]?.length) {
userRecord["sessions"] = [session];
} else {
userRecord.sessions = removeExpiredSessions(userRecord.sessions);
userRecord.sessions.push(session);
}
await payload.db.updateOne({
id: userRecord.id,
collection: collections.usersCollection,
data: userRecord,
req: request,
returning: false
});
}
const cookieName = useAdmin ? `${payload.config.cookiePrefix}-token` : `__${pluginType}-${APP_COOKIE_SUFFIX}`;
cookies = [
...await createSessionCookies(cookieName, secret, {
id: userRecord.id,
email,
sid: sessionID,
collection: collections.usersCollection
}, useAdmin ? collectionConfig?.auth.tokenExpiration : undefined)
];
cookies = invalidateOAuthCookies(cookies);
const successRedirectionURL = new URL(`${payload.config.serverURL}${successRedirectPath}`);
const res = new Response(null, {
status: 302,
headers: {
Location: successRedirectionURL.href
}
});
for (const c of cookies) {
res.headers.append("Set-Cookie", c);
}
return res;
}
export {
OAuthAuthentication
};