-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Closed
Description
Describe the Bug
I'm using a Custom Strategy to login via OpenID without the login form:
This is my auth file:
import { type Payload, PayloadHandler, PayloadRequest, User, parseCookies, AuthStrategyFunction, AuthStrategyFunctionArgs, AuthStrategyResult } from 'payload'
import * as openid from 'openid-client'
import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';
const server: URL = new URL(process.env.OPEN_ID_URL || ''),
clientId: string = process.env.OPEN_ID_CLIENT || '',
clientSecret: string = process.env.OPEN_ID_SECRET || '',
redirect_uri: string = `${process.env.SERVER_URL}/admin/login`,
scope: string = process.env.OPEN_ID_SCOPE;
const jwks = jwksClient({
jwksUri: process.env.OPEN_ID_KEYS || ''
});
const config: openid.Configuration = await openid.discovery(server, clientId, clientSecret);
export const decode = (token: string) => new Promise(next => {
var decoded = jwt.decode(token, {
complete: true
});
const kid = decoded?.header?.kid;
jwks.getSigningKey(kid, (error, key: any) => !error ? jwt.verify(token, key.publicKey || key.rsaPublicKey, (err: any, decoded: any) => next(!err ? decoded : null)) : next(null));
})
// endpoint: /api/login
export const login: PayloadHandler = async (req: PayloadRequest): Promise<Response> => {
let code_verifier: string = openid.randomPKCECodeVerifier(),
code_challenge: string = await openid.calculatePKCECodeChallenge(code_verifier),
state!: string,
nonce!: string,
parameters: Record<string, string> = {
redirect_uri,
scope,
code_challenge,
code_challenge_method: 'S256',
response_type: 'id_token'
}
if (!config.serverMetadata().supportsPKCE()) {
state = openid.randomState();
parameters.state = state;
nonce = openid.randomNonce();
parameters.nonce = nonce;
}
let redirectTo: URL = openid.buildAuthorizationUrl(config, parameters);
return Response.redirect(redirectTo.href);
};
const getUser = async (payload: Payload, email?: string): Promise<User | null> => {
if (!email) return null;
const find = await payload.find({
collection: 'users',
where: {
email: {
equals: email
}
}
});
return !find?.docs?.[0]?.email ? null : {
...find.docs[0],
email: find.docs[0].email || '',
collection: 'users'
};
}
// endpoint: /api/login/:token, called in BeforeLogin.tsx, if returns the user, the provided token is set to a cookie
export const check: PayloadHandler = async (req: PayloadRequest): Promise<Response> => {
if (!req?.routeParams?.token) return Response.error();
const user = await decode(typeof req.routeParams.token !== 'string' ? '' : req.routeParams.token) as User | null;
return !user?.email ? Response.error() : Response.json(user)
};
// collection strategy
export const authenticate: AuthStrategyFunction = async ({ payload, headers }: AuthStrategyFunctionArgs): Promise<AuthStrategyResult> => {
const cookie = parseCookies(headers),
token = cookie.get('token');
if (!token) return { user: null }; // /api/users/me stops here
const data: any = await decode(token);
if (!data?.email) return { user: null }
let user: User | null = await getUser(payload, data.email);
if (!user) {
await payload.create({
collection: 'users',
data: {
name: data.name,
email: data.email
}
});
user = await getUser(payload, data.email);
}
return {
user
};
};But the response from /api/users/me is this one:
{
"user":null,
"message":"Account"
}With a custom API this also returns null in the user property:
const payload = await getPayload({ config })
const requestHeaders = await headers()
const { user } = await payload.auth({ headers: requestHeaders })This is the request:
fetch('/api/test', {
method: 'POST',
credentials: 'include'
})Link to the code that reproduces this issue
https://github.com/RPdvtPT/payload-strategy-test
Reproduction Steps
- create a sample project based on the blank template
- apply the strategy
- after login, check
/api/users/meresponses
Which area(s) are affected? (Select all that apply)
Not sure
Environment Info
- payload: 3.11.0
- react: 19.0.0
- next: 15.1.2
- jsonwebtoken: 9.0.2
- jwks-rsa: 3.1.0
- openid-client: 6.1.7
Metadata
Metadata
Assignees
Labels
No labels