payload-auth-plugin
Version:
Authentication plugin for Payload CMS
115 lines (102 loc) • 3.44 kB
text/typescript
import * as oauth from "oauth4webapi"
import { parseCookies, type PayloadRequest } from "payload"
import { generateProviderCustomEmail } from "../../../providers/utils.js"
import type { OAuth2ProviderConfig } from "../../../types.js"
import { MissingOrInvalidSession } from "../../errors/consoleErrors.js"
import { getCallbackURL } from "../../utils/cb.js"
import { OAuthAuthentication } from "./oauth_authentication.js"
export async function OAuth2Callback(
pluginType: string,
request: PayloadRequest,
providerConfig: OAuth2ProviderConfig,
collections: {
usersCollection: string
accountsCollection: string
},
allowOAuthAutoSignUp: boolean,
useAdmin: boolean,
secret: string,
successRedirectPath: string,
errorRedirectPath: string,
additionalScope?: string,
): Promise<Response> {
const parsedCookies = parseCookies(request.headers)
const code_verifier = parsedCookies.get("__session-code-verifier")
const state = parsedCookies.get("__session-oauth-state")
if (!code_verifier) {
throw new MissingOrInvalidSession()
}
const { client_id, client_secret, authorization_server, client_auth_type } =
providerConfig
const client: oauth.Client = {
client_id,
}
const clientAuth =
client_auth_type === "client_secret_basic"
? oauth.ClientSecretBasic(client_secret ?? "")
: oauth.ClientSecretPost(client_secret ?? "")
const current_url = new URL(request.url as string) as URL
const callback_url = getCallbackURL(
request.payload.config.serverURL,
pluginType,
providerConfig.id,
)
const as = authorization_server
const params = oauth.validateAuthResponse(as, client, current_url, state)
const grantResponse = await oauth.authorizationCodeGrantRequest(
as,
client,
clientAuth,
params,
callback_url.toString(),
code_verifier,
)
const body = (await grantResponse.json()) as { scope: string | string[] }
let response = new Response(JSON.stringify(body), grantResponse)
if (Array.isArray(body.scope)) {
body.scope = body.scope.join(" ")
response = new Response(JSON.stringify(body), grantResponse)
}
const token_result = await oauth.processAuthorizationCodeResponse(
as,
client,
response,
)
const userInfoResponse = await oauth.userInfoRequest(
as,
client,
token_result.access_token,
)
const userInfo = (await userInfoResponse.json()) as Record<string, string>
const email = providerConfig.emailDomain ? generateProviderCustomEmail(providerConfig.name.toLowerCase().trim()
.replace(/[^a-z0-9\s-]/g, "")
.replace(/\s+/g, "-")
.replace(/-+/g, "-"), providerConfig.emailDomain) : userInfo.email
const userData = {
email,
name: userInfo.name ?? "",
sub: userInfo.sub,
scope:
providerConfig.scope + (additionalScope ? ` ${additionalScope}` : ""),
issuer: providerConfig.authorization_server.issuer,
picture: userInfo.picture ?? "",
access_token: token_result.access_token,
refresh_token: token_result.refresh_token ?? "",
expires_in:
typeof token_result.expires_in === "number"
? token_result.expires_in
: undefined,
claims: {}, // TODO: Take a look how claims work with OAuth2
}
return await OAuthAuthentication(
pluginType,
collections,
allowOAuthAutoSignUp,
useAdmin,
secret,
request,
successRedirectPath,
errorRedirectPath,
userData,
)
}