payload-zitadel-plugin 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/handlers/callback.d.ts.map +1 -1
- package/dist/handlers/callback.js +0 -1
- package/dist/handlers/callback.js.map +1 -1
- package/dist/utils/redirects.d.ts.map +1 -1
- package/dist/utils/redirects.js +2 -6
- package/dist/utils/redirects.js.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
@@ -12,7 +12,7 @@ Thus, the user collection in PayloadCMS becomes just a shadow of the information
|
|
12
12
|
## Install
|
13
13
|
|
14
14
|
```shell
|
15
|
-
pnpm add payload-zitadel-plugin@0.4.
|
15
|
+
pnpm add payload-zitadel-plugin@0.4.1
|
16
16
|
```
|
17
17
|
|
18
18
|
## Configuration
|
@@ -69,14 +69,14 @@ export default buildConfig({
|
|
69
69
|
}
|
70
70
|
*/
|
71
71
|
|
72
|
-
// if you want to manually control what
|
72
|
+
// if you want to manually control what happens after a successful login
|
73
73
|
// afterLogin: (req) => NextResponse.redirect('...')
|
74
74
|
|
75
|
-
// if you want to manually control what
|
75
|
+
// if you want to manually control what happens after a successful logout
|
76
76
|
// afterLogout: (req) => NextResponse.redirect('...')
|
77
77
|
|
78
78
|
// following properties are only needed if you want to authenticate clients (e.g. a mobile app) for the API
|
79
|
-
// if the users are just
|
79
|
+
// if the users are just visiting the CMS via a browser you can ignore all of them
|
80
80
|
// otherwise create in Zitadel a new App->API->JWT and copy the Client ID, Key ID and the Key itself
|
81
81
|
/*
|
82
82
|
api: {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["../../src/handlers/callback.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,sBAAsB,EAAuC,MAAM,aAAa,CAAA;AAGxF,eAAO,MAAM,QAAQ,EAAE,
|
1
|
+
{"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["../../src/handlers/callback.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,sBAAsB,EAAuC,MAAM,aAAa,CAAA;AAGxF,eAAO,MAAM,QAAQ,EAAE,sBAiLtB,CAAA"}
|
@@ -7,7 +7,6 @@ export const callback = ({ issuerURL, clientId, fields, afterLogin, afterLogout
|
|
7
7
|
const { config, secret } = payload;
|
8
8
|
const { code } = query;
|
9
9
|
const state = getState(req);
|
10
|
-
console.log('callback with state:', JSON.stringify(state));
|
11
10
|
const cookieStore = await cookies();
|
12
11
|
if (state.invokedBy == 'end_session') {
|
13
12
|
[
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../src/handlers/callback.ts"],"sourcesContent":["import {SignJWT, decodeJwt} from 'jose'\nimport {cookies} from 'next/headers.js'\nimport {COOKIES, ENDPOINT_PATHS, ROLES_KEY, ROUTES} from '../constants.js'\nimport {ZitadelCallbackHandler, ZitadelCallbackQuery, ZitadelIdToken} from '../types.js'\nimport {getAuthBaseURL, getAuthSlug, getState} from '../utils/index.js'\n\nexport const callback: ZitadelCallbackHandler = ({\n issuerURL,\n clientId,\n fields,\n afterLogin,\n afterLogout\n }) => async (req) => {\n\n const {payload, query} = req\n\n const {config, secret} = payload\n\n const {code} = query as ZitadelCallbackQuery\n\n const state = getState(req)\n\n
|
1
|
+
{"version":3,"sources":["../../src/handlers/callback.ts"],"sourcesContent":["import {SignJWT, decodeJwt} from 'jose'\nimport {cookies} from 'next/headers.js'\nimport {COOKIES, ENDPOINT_PATHS, ROLES_KEY, ROUTES} from '../constants.js'\nimport {ZitadelCallbackHandler, ZitadelCallbackQuery, ZitadelIdToken} from '../types.js'\nimport {getAuthBaseURL, getAuthSlug, getState} from '../utils/index.js'\n\nexport const callback: ZitadelCallbackHandler = ({\n issuerURL,\n clientId,\n fields,\n afterLogin,\n afterLogout\n }) => async (req) => {\n\n const {payload, query} = req\n\n const {config, secret} = payload\n\n const {code} = query as ZitadelCallbackQuery\n\n const state = getState(req)\n\n const cookieStore = await cookies()\n\n if (state.invokedBy == 'end_session') {\n\n [COOKIES.logout, COOKIES.idToken].forEach(cookie => cookieStore.delete(cookie))\n\n return afterLogout(req)\n\n }\n\n const codeVerifier = cookieStore.get(COOKIES.pkce.name)?.value\n\n if (!code) {\n return Response.json({\n status: 'error',\n message: 'no code provided to verify'\n })\n }\n\n if (!codeVerifier) {\n return Response.json({\n status: 'error',\n message: 'code verifier not found (associated http-only cookie is empty)'\n })\n }\n\n const tokenQueryData = {\n grant_type: 'authorization_code',\n code,\n redirect_uri: getAuthBaseURL(config) + ROUTES.callback,\n client_id: clientId,\n code_verifier: codeVerifier\n }\n\n const tokenEndpoint = issuerURL + ENDPOINT_PATHS.token\n\n const tokenResponse = await fetch(new URL(tokenEndpoint), {\n method: 'POST',\n body: new URLSearchParams(tokenQueryData)\n })\n\n if (!tokenResponse.ok) {\n return Response.json({\n status: 'error',\n message: 'error while communicating with token endpoint',\n details: {\n tokenEndpoint,\n tokenQuery: tokenQueryData,\n tokenResponseCode: `${tokenResponse.status} - ${tokenResponse.statusText}`\n }\n })\n }\n\n const tokenJson = await tokenResponse.json()\n\n const {id_token: idToken} = tokenJson\n\n if (!idToken) {\n return Response.json({\n status: 'error',\n message: 'token could not be retrieved from this response',\n details: {\n responseData: tokenJson\n }\n })\n }\n\n let decodedIdToken\n\n try {\n\n decodedIdToken = decodeJwt<ZitadelIdToken>(idToken)\n\n } catch (e) {\n\n return Response.json({\n status: 'error',\n message: `error during decoding: ${JSON.stringify(e)}`,\n details: {\n idToken\n }\n })\n\n }\n\n const idpId = decodedIdToken.sub\n\n const userData = {\n [fields.name.name]: decodedIdToken.name,\n [fields.email.name]: decodedIdToken.email,\n [fields.image.name]: decodedIdToken.picture,\n [fields.roles.name]: Object.keys(decodedIdToken[ROLES_KEY] ?? {})\n .map(key => ({[fields.roleFields.name.name]: key}))\n }\n\n if (!idpId) {\n return Response.json({\n status: 'error',\n message: 'token is not complete (id not found)',\n details: {\n idToken,\n decodedIdToken,\n idpId\n }\n })\n }\n\n try {\n\n const authSlug = getAuthSlug(config)\n\n const {docs, totalDocs} = await payload.find({\n collection: authSlug,\n where: {\n [fields.id.name]: {\n equals: idpId\n }\n }\n })\n\n if (totalDocs) {\n await payload.update({\n collection: authSlug,\n id: docs[0].id,\n data: userData\n })\n } else {\n await payload.create({\n collection: authSlug,\n data: {\n [fields.id.name]: idpId,\n ...userData\n }\n })\n }\n\n } catch (e) {\n\n return Response.json({\n status: 'error',\n message: `error while creating/updating user: ${JSON.stringify(e)}`,\n details: {\n idpId\n }\n })\n\n }\n\n cookieStore.delete(COOKIES.pkce)\n\n cookieStore.set({\n ...COOKIES.idToken,\n value: await new SignJWT(decodedIdToken)\n .setProtectedHeader({alg: 'HS256'})\n .setIssuedAt()\n .sign(new TextEncoder().encode(secret)),\n maxAge: 900\n })\n\n return afterLogin(req)\n\n}"],"names":["SignJWT","decodeJwt","cookies","COOKIES","ENDPOINT_PATHS","ROLES_KEY","ROUTES","getAuthBaseURL","getAuthSlug","getState","callback","issuerURL","clientId","fields","afterLogin","afterLogout","req","payload","query","config","secret","code","state","cookieStore","invokedBy","logout","idToken","forEach","cookie","delete","codeVerifier","get","pkce","name","value","Response","json","status","message","tokenQueryData","grant_type","redirect_uri","client_id","code_verifier","tokenEndpoint","token","tokenResponse","fetch","URL","method","body","URLSearchParams","ok","details","tokenQuery","tokenResponseCode","statusText","tokenJson","id_token","responseData","decodedIdToken","e","JSON","stringify","idpId","sub","userData","email","image","picture","roles","Object","keys","map","key","roleFields","authSlug","docs","totalDocs","find","collection","where","id","equals","update","data","create","set","setProtectedHeader","alg","setIssuedAt","sign","TextEncoder","encode","maxAge"],"mappings":"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"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"redirects.d.ts","sourceRoot":"","sources":["../../src/utils/redirects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,SAAS,CAAA;AAGtC,OAAO,EAAC,qBAAqB,EAAC,MAAM,aAAa,CAAA;AAIjD,eAAO,MAAM,eAAe,EAAE,cAC0D,CAAA;AAExF,eAAO,MAAM,eAAe,EAAE,
|
1
|
+
{"version":3,"file":"redirects.d.ts","sourceRoot":"","sources":["../../src/utils/redirects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,SAAS,CAAA;AAGtC,OAAO,EAAC,qBAAqB,EAAC,MAAM,aAAa,CAAA;AAIjD,eAAO,MAAM,eAAe,EAAE,cAC0D,CAAA;AAExF,eAAO,MAAM,eAAe,EAAE,qBASrB,CAAA"}
|
package/dist/utils/redirects.js
CHANGED
@@ -3,8 +3,7 @@ import { AUTHORIZE_QUERY, ENDPOINT_PATHS, ROUTES } from '../constants.js';
|
|
3
3
|
import { createState, getState } from './state.js';
|
4
4
|
import { getAuthBaseURL } from './urls.js';
|
5
5
|
export const defaultRedirect = (req)=>NextResponse.redirect(req.payload.config.serverURL + (getState(req).redirect ?? ''));
|
6
|
-
export const requestRedirect = ({ req, issuerURL, clientId, invokedBy, codeChallenge })=>{
|
7
|
-
const redirectURL = `${issuerURL}${ENDPOINT_PATHS[invokedBy]}?${new URLSearchParams({
|
6
|
+
export const requestRedirect = ({ req, issuerURL, clientId, invokedBy, codeChallenge })=>NextResponse.redirect(`${issuerURL}${ENDPOINT_PATHS[invokedBy]}?${new URLSearchParams({
|
8
7
|
client_id: clientId,
|
9
8
|
[`${invokedBy == 'authorize' ? '' : 'post_logout_'}redirect_uri`]: getAuthBaseURL(req.payload.config) + ROUTES.callback,
|
10
9
|
state: createState(req, invokedBy),
|
@@ -12,9 +11,6 @@ export const requestRedirect = ({ req, issuerURL, clientId, invokedBy, codeChall
|
|
12
11
|
code_challenge: codeChallenge,
|
13
12
|
...AUTHORIZE_QUERY
|
14
13
|
} : {}
|
15
|
-
})}
|
16
|
-
console.log('requesting redirect to:', redirectURL);
|
17
|
-
return NextResponse.redirect(redirectURL);
|
18
|
-
};
|
14
|
+
})}`);
|
19
15
|
|
20
16
|
//# sourceMappingURL=redirects.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../src/utils/redirects.ts"],"sourcesContent":["import {PayloadHandler} from 'payload'\nimport {NextResponse} from 'next/server.js'\nimport {AUTHORIZE_QUERY, ENDPOINT_PATHS, ROUTES} from '../constants.js'\nimport {ZitadelRequestHandler} from '../types.js'\nimport {createState, getState} from './state.js'\nimport {getAuthBaseURL} from './urls.js'\n\nexport const defaultRedirect: PayloadHandler = (req) =>\n NextResponse.redirect(req.payload.config.serverURL + (getState(req).redirect ?? ''))\n\nexport const requestRedirect: ZitadelRequestHandler = ({req, issuerURL, clientId, invokedBy, codeChallenge})
|
1
|
+
{"version":3,"sources":["../../src/utils/redirects.ts"],"sourcesContent":["import {PayloadHandler} from 'payload'\nimport {NextResponse} from 'next/server.js'\nimport {AUTHORIZE_QUERY, ENDPOINT_PATHS, ROUTES} from '../constants.js'\nimport {ZitadelRequestHandler} from '../types.js'\nimport {createState, getState} from './state.js'\nimport {getAuthBaseURL} from './urls.js'\n\nexport const defaultRedirect: PayloadHandler = (req) =>\n NextResponse.redirect(req.payload.config.serverURL + (getState(req).redirect ?? ''))\n\nexport const requestRedirect: ZitadelRequestHandler = ({req, issuerURL, clientId, invokedBy, codeChallenge}) =>\n NextResponse.redirect(`${issuerURL}${ENDPOINT_PATHS[invokedBy]}?${new URLSearchParams({\n client_id: clientId,\n [`${invokedBy == 'authorize' ? '' : 'post_logout_'}redirect_uri`]: getAuthBaseURL(req.payload.config) + ROUTES.callback,\n state: createState(req, invokedBy),\n ...invokedBy == 'authorize' ? {\n code_challenge: codeChallenge,\n ...AUTHORIZE_QUERY\n } : {}\n })}`)"],"names":["NextResponse","AUTHORIZE_QUERY","ENDPOINT_PATHS","ROUTES","createState","getState","getAuthBaseURL","defaultRedirect","req","redirect","payload","config","serverURL","requestRedirect","issuerURL","clientId","invokedBy","codeChallenge","URLSearchParams","client_id","callback","state","code_challenge"],"mappings":"AACA,SAAQA,YAAY,QAAO,iBAAgB;AAC3C,SAAQC,eAAe,EAAEC,cAAc,EAAEC,MAAM,QAAO,kBAAiB;AAEvE,SAAQC,WAAW,EAAEC,QAAQ,QAAO,aAAY;AAChD,SAAQC,cAAc,QAAO,YAAW;AAExC,OAAO,MAAMC,kBAAkC,CAACC,MAC5CR,aAAaS,QAAQ,CAACD,IAAIE,OAAO,CAACC,MAAM,CAACC,SAAS,GAAIP,CAAAA,SAASG,KAAKC,QAAQ,IAAI,EAAC,GAAG;AAExF,OAAO,MAAMI,kBAAyC,CAAC,EAACL,GAAG,EAAEM,SAAS,EAAEC,QAAQ,EAAEC,SAAS,EAAEC,aAAa,EAAC,GACvGjB,aAAaS,QAAQ,CAAC,GAAGK,YAAYZ,cAAc,CAACc,UAAU,CAAC,CAAC,EAAE,IAAIE,gBAAgB;QAClFC,WAAWJ;QACX,CAAC,GAAGC,aAAa,cAAc,KAAK,eAAe,YAAY,CAAC,CAAC,EAAEV,eAAeE,IAAIE,OAAO,CAACC,MAAM,IAAIR,OAAOiB,QAAQ;QACvHC,OAAOjB,YAAYI,KAAKQ;QACxB,GAAGA,aAAa,cAAc;YAC1BM,gBAAgBL;YAChB,GAAGhB,eAAe;QACtB,IAAI,CAAC,CAAC;IACV,IAAI,EAAC"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "payload-zitadel-plugin",
|
3
|
-
"version": "0.4.
|
3
|
+
"version": "0.4.1",
|
4
4
|
"description": "plugin for Payload CMS, which enables authentication via Zitadel IdP",
|
5
5
|
"type": "module",
|
6
6
|
"license": "MIT",
|
@@ -36,18 +36,18 @@
|
|
36
36
|
"dist"
|
37
37
|
],
|
38
38
|
"dependencies": {
|
39
|
-
"@payloadcms/next": "^3.
|
40
|
-
"@payloadcms/translations": "^3.
|
41
|
-
"@payloadcms/ui": "^3.
|
39
|
+
"@payloadcms/next": "^3.12.0",
|
40
|
+
"@payloadcms/translations": "^3.12.0",
|
41
|
+
"@payloadcms/ui": "^3.12.0",
|
42
42
|
"jose": "^5.9.6",
|
43
43
|
"next": "^15.1.3",
|
44
|
-
"payload": "^3.
|
44
|
+
"payload": "^3.12.0",
|
45
45
|
"react": "^19.0.0",
|
46
46
|
"react-dom": "^19.0.0"
|
47
47
|
},
|
48
48
|
"devDependencies": {
|
49
49
|
"@swc/cli": "^0.5.2",
|
50
|
-
"@swc/core": "^1.10.
|
50
|
+
"@swc/core": "^1.10.4",
|
51
51
|
"@types/node": "^22.10.2",
|
52
52
|
"@types/react": "^19.0.2",
|
53
53
|
"@types/react-dom": "^19.0.2",
|