payload-zitadel-plugin 0.2.36 → 0.2.38
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 +1 -1
- package/dist/handlers/callback.d.ts.map +1 -1
- package/dist/handlers/callback.js +4 -2
- package/dist/handlers/callback.js.map +1 -1
- package/dist/strategy.js +6 -10
- package/dist/strategy.js.map +1 -1
- package/package.json +14 -15
package/README.md
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["../../src/handlers/callback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,SAAS,CAAA;AAItC,OAAO,EAA2C,gBAAgB,EAAC,MAAM,aAAa,CAAA;AAGtF,eAAO,MAAM,QAAQ,cAAe,gBAAgB,KAAG,
|
1
|
+
{"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["../../src/handlers/callback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,SAAS,CAAA;AAItC,OAAO,EAA2C,gBAAgB,EAAC,MAAM,aAAa,CAAA;AAGtF,eAAO,MAAM,QAAQ,cAAe,gBAAgB,KAAG,cAoEtD,CAAA"}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { cookies } from 'next/headers.js';
|
2
2
|
import process from 'node:process';
|
3
|
-
import
|
3
|
+
import { SignJWT, decodeJwt } from 'jose';
|
4
4
|
import { COOKIES } from '../constants.js';
|
5
5
|
export const callback = (onSuccess)=>async ({ payload: { config, secret }, query: { code, state } })=>{
|
6
6
|
const { admin: { custom: { zitadel: { issuerURL, clientId, callbackURL } } } } = config;
|
@@ -23,7 +23,9 @@ export const callback = (onSuccess)=>async ({ payload: { config, secret }, query
|
|
23
23
|
cookieStore.delete(COOKIES.pkce);
|
24
24
|
cookieStore.set({
|
25
25
|
name: COOKIES.idToken,
|
26
|
-
value:
|
26
|
+
value: await new SignJWT(decodeJwt(id_token)).setProtectedHeader({
|
27
|
+
alg: 'HS256'
|
28
|
+
}).setIssuedAt().sign(new TextEncoder().encode(secret)),
|
27
29
|
httpOnly: true,
|
28
30
|
path: '/',
|
29
31
|
sameSite: 'lax',
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../src/handlers/callback.ts"],"sourcesContent":["import {PayloadHandler} from 'payload'\nimport {cookies} from 'next/headers.js'\nimport process from 'node:process'\nimport
|
1
|
+
{"version":3,"sources":["../../src/handlers/callback.ts"],"sourcesContent":["import {PayloadHandler} from 'payload'\nimport {cookies} from 'next/headers.js'\nimport process from 'node:process'\nimport {SignJWT, decodeJwt} from 'jose'\nimport {PayloadConfigWithZitadel, ZitadelIdToken, ZitadelOnSuccess} from '../types.js'\nimport {COOKIES} from '../constants.js'\n\nexport const callback = (onSuccess: ZitadelOnSuccess): PayloadHandler => async ({\n payload: {config, secret},\n query: {code, state}\n }) => {\n\n const {admin: {custom: {zitadel: {issuerURL, clientId, callbackURL}}}} = config as PayloadConfigWithZitadel\n\n const cookieStore = await cookies()\n\n const code_verifier = cookieStore.get(COOKIES.pkce)?.value\n\n if (code_verifier) {\n\n const response = await fetch(new URL(`${issuerURL}/oauth/v2/token`), {\n method: 'POST',\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code: code as string,\n redirect_uri: callbackURL,\n client_id: clientId,\n code_verifier\n })\n })\n\n if (response.ok) {\n\n const {id_token} = await response.json()\n\n if (id_token) {\n\n cookieStore.delete(COOKIES.pkce)\n\n cookieStore.set({\n name: COOKIES.idToken,\n value: await new SignJWT(decodeJwt<ZitadelIdToken>(id_token))\n .setProtectedHeader({alg: 'HS256'})\n .setIssuedAt()\n .sign(new TextEncoder().encode(secret)),\n httpOnly: true,\n path: '/',\n sameSite: 'lax',\n maxAge: 900,\n secure: process.env.NODE_ENV == 'production'\n })\n\n return onSuccess(new URLSearchParams(atob(state as string ?? '')))\n\n }\n\n return Response.json({\n status: 'error',\n message: 'token could not be retrieved from the response'\n })\n\n }\n\n return Response.json({\n status: 'error',\n message: 'error while communicating with token endpoint'\n })\n\n }\n\n return Response.json({\n status: 'error',\n message: 'code verifier not found (associated http-only cookie is empty)'\n })\n\n}"],"names":["cookies","process","SignJWT","decodeJwt","COOKIES","callback","onSuccess","payload","config","secret","query","code","state","admin","custom","zitadel","issuerURL","clientId","callbackURL","cookieStore","code_verifier","get","pkce","value","response","fetch","URL","method","body","URLSearchParams","grant_type","redirect_uri","client_id","ok","id_token","json","delete","set","name","idToken","setProtectedHeader","alg","setIssuedAt","sign","TextEncoder","encode","httpOnly","path","sameSite","maxAge","secure","env","NODE_ENV","atob","Response","status","message"],"mappings":"AACA,SAAQA,OAAO,QAAO,kBAAiB;AACvC,OAAOC,aAAa,eAAc;AAClC,SAAQC,OAAO,EAAEC,SAAS,QAAO,OAAM;AAEvC,SAAQC,OAAO,QAAO,kBAAiB;AAEvC,OAAO,MAAMC,WAAW,CAACC,YAAgD,OAAO,EACIC,SAAS,EAACC,MAAM,EAAEC,MAAM,EAAC,EACzBC,OAAO,EAACC,IAAI,EAAEC,KAAK,EAAC,EACvB;QAE7E,MAAM,EAACC,OAAO,EAACC,QAAQ,EAACC,SAAS,EAACC,SAAS,EAAEC,QAAQ,EAAEC,WAAW,EAAC,EAAC,EAAC,EAAC,GAAGV;QAEzE,MAAMW,cAAc,MAAMnB;QAE1B,MAAMoB,gBAAgBD,YAAYE,GAAG,CAACjB,QAAQkB,IAAI,GAAGC;QAErD,IAAIH,eAAe;YAEf,MAAMI,WAAW,MAAMC,MAAM,IAAIC,IAAI,GAAGV,UAAU,eAAe,CAAC,GAAG;gBACjEW,QAAQ;gBACRC,MAAM,IAAIC,gBAAgB;oBACtBC,YAAY;oBACZnB,MAAMA;oBACNoB,cAAcb;oBACdc,WAAWf;oBACXG;gBACJ;YACJ;YAEA,IAAII,SAASS,EAAE,EAAE;gBAEb,MAAM,EAACC,QAAQ,EAAC,GAAG,MAAMV,SAASW,IAAI;gBAEtC,IAAID,UAAU;oBAEVf,YAAYiB,MAAM,CAAChC,QAAQkB,IAAI;oBAE/BH,YAAYkB,GAAG,CAAC;wBACZC,MAAMlC,QAAQmC,OAAO;wBACrBhB,OAAO,MAAM,IAAIrB,QAAQC,UAA0B+B,WAC9CM,kBAAkB,CAAC;4BAACC,KAAK;wBAAO,GAChCC,WAAW,GACXC,IAAI,CAAC,IAAIC,cAAcC,MAAM,CAACpC;wBACnCqC,UAAU;wBACVC,MAAM;wBACNC,UAAU;wBACVC,QAAQ;wBACRC,QAAQjD,QAAQkD,GAAG,CAACC,QAAQ,IAAI;oBACpC;oBAEA,OAAO9C,UAAU,IAAIuB,gBAAgBwB,KAAKzC,SAAmB;gBAEjE;gBAEA,OAAO0C,SAASnB,IAAI,CAAC;oBACjBoB,QAAQ;oBACRC,SAAS;gBACb;YAEJ;YAEA,OAAOF,SAASnB,IAAI,CAAC;gBACjBoB,QAAQ;gBACRC,SAAS;YACb;QAEJ;QAEA,OAAOF,SAASnB,IAAI,CAAC;YACjBoB,QAAQ;YACRC,SAAS;QACb;IAEJ,EAAC"}
|
package/dist/strategy.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import
|
1
|
+
import { SignJWT, jwtVerify } from 'jose';
|
2
2
|
import { cookies } from 'next/headers.js';
|
3
3
|
import { COOKIES } from './constants.js';
|
4
4
|
export const zitadelStrategy = ({ authSlug, fieldsConfig, strategyName, issuerURL, enableAPI, apiClientId, apiKeyId, apiKey })=>({
|
@@ -17,14 +17,10 @@ export const zitadelStrategy = ({ authSlug, fieldsConfig, strategyName, issuerUR
|
|
17
17
|
},
|
18
18
|
body: new URLSearchParams({
|
19
19
|
'client_assertion_type': 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
|
20
|
-
'client_assertion':
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
issuer: apiClientId,
|
25
|
-
keyid: apiKeyId,
|
26
|
-
subject: apiClientId
|
27
|
-
}),
|
20
|
+
'client_assertion': await new SignJWT().setProtectedHeader({
|
21
|
+
alg: 'RS256',
|
22
|
+
kid: apiKeyId
|
23
|
+
}).setIssuer(apiClientId).setAudience(issuerURL).setSubject(apiClientId).setIssuedAt().setExpirationTime('1h').sign(new TextEncoder().encode(apiKey)),
|
28
24
|
'token': authHeader.split(' ')[1]
|
29
25
|
})
|
30
26
|
});
|
@@ -38,7 +34,7 @@ export const zitadelStrategy = ({ authSlug, fieldsConfig, strategyName, issuerUR
|
|
38
34
|
}
|
39
35
|
// in case of normal browsing
|
40
36
|
if (!idp_id && cookieStore.has(COOKIES.idToken)) {
|
41
|
-
id_token =
|
37
|
+
id_token = (await jwtVerify(cookieStore.get(COOKIES.idToken)?.value ?? '', new TextEncoder().encode(payload.secret))).payload;
|
42
38
|
idp_id = id_token.sub;
|
43
39
|
}
|
44
40
|
// search for associated user; if not found, create one
|
package/dist/strategy.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/strategy.ts"],"sourcesContent":["import {ZitadelIdToken, ZitadelStrategyType} from './types.js'\nimport
|
1
|
+
{"version":3,"sources":["../src/strategy.ts"],"sourcesContent":["import {ZitadelIdToken, ZitadelStrategyType} from './types.js'\nimport {SignJWT, jwtVerify} from 'jose'\nimport {cookies} from 'next/headers.js'\nimport {COOKIES} from './constants.js'\n\nexport const zitadelStrategy: ZitadelStrategyType = ({\n authSlug,\n fieldsConfig,\n strategyName,\n issuerURL,\n enableAPI,\n apiClientId,\n apiKeyId,\n apiKey\n }) => ({\n name: strategyName,\n authenticate: async ({headers, payload}) => {\n\n let id, idp_id, id_token\n\n const cookieStore = await cookies()\n\n if (enableAPI) {\n // in case of incoming API call from the app\n const authHeader = headers.get('Authorization')\n if (authHeader?.includes('Bearer')) {\n const introspect = await fetch(`${issuerURL}/oauth/v2/introspect`, {\n method: 'post',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded'\n },\n body: new URLSearchParams({\n 'client_assertion_type': 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',\n 'client_assertion': await new SignJWT()\n .setProtectedHeader({alg: 'RS256', kid: apiKeyId})\n .setIssuer(apiClientId)\n .setAudience(issuerURL)\n .setSubject(apiClientId)\n .setIssuedAt()\n .setExpirationTime('1h')\n .sign(new TextEncoder().encode(apiKey)),\n 'token': authHeader.split(' ')[1]\n })\n })\n if (introspect.ok) {\n const data = await introspect.json()\n if (data?.active) {\n idp_id = data.sub\n }\n }\n }\n }\n\n // in case of normal browsing\n if (!idp_id && cookieStore.has(COOKIES.idToken)) {\n id_token = (await jwtVerify<ZitadelIdToken>(cookieStore.get(COOKIES.idToken)?.value ?? '', new TextEncoder().encode(payload.secret))).payload\n idp_id = id_token.sub\n }\n\n // search for associated user; if not found, create one\n if (idp_id) {\n const {docs, totalDocs} = await payload.find({\n collection: authSlug,\n where: {\n [fieldsConfig.id.name]: {\n equals: idp_id\n }\n }\n })\n id = totalDocs ? docs[0].id : (await payload.create({\n collection: authSlug,\n data: {\n [fieldsConfig.id.name]: idp_id\n }\n })).id\n }\n\n // update user information if possible\n if (id && id_token) {\n await payload.update({\n collection: authSlug,\n id,\n data: {\n [fieldsConfig.name.name]: id_token.name,\n [fieldsConfig.email.name]: id_token.email,\n [fieldsConfig.image.name]: id_token.picture,\n [fieldsConfig.roles.name]: Object.keys(id_token['urn:zitadel:iam:org:project:roles'] ?? {})\n .map(key => ({[fieldsConfig.roleFields.name.name]: key}))\n }\n })\n }\n\n return {\n user: id ? {\n collection: authSlug,\n id\n } : null\n }\n\n }\n})"],"names":["SignJWT","jwtVerify","cookies","COOKIES","zitadelStrategy","authSlug","fieldsConfig","strategyName","issuerURL","enableAPI","apiClientId","apiKeyId","apiKey","name","authenticate","headers","payload","id","idp_id","id_token","cookieStore","authHeader","get","includes","introspect","fetch","method","body","URLSearchParams","setProtectedHeader","alg","kid","setIssuer","setAudience","setSubject","setIssuedAt","setExpirationTime","sign","TextEncoder","encode","split","ok","data","json","active","sub","has","idToken","value","secret","docs","totalDocs","find","collection","where","equals","create","update","email","image","picture","roles","Object","keys","map","key","roleFields","user"],"mappings":"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"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "payload-zitadel-plugin",
|
3
|
-
"version": "0.2.
|
3
|
+
"version": "0.2.38",
|
4
4
|
"description": "plugin for Payload CMS, which enables authentication via Zitadel IdP",
|
5
5
|
"type": "module",
|
6
6
|
"license": "MIT",
|
@@ -36,27 +36,26 @@
|
|
36
36
|
"dist"
|
37
37
|
],
|
38
38
|
"dependencies": {
|
39
|
-
"@payloadcms/next": "3.0.0-beta.
|
40
|
-
"@payloadcms/translations": "3.0.0-beta.
|
41
|
-
"@payloadcms/ui": "3.0.0-beta.
|
42
|
-
"
|
43
|
-
"next": "15.0.
|
44
|
-
"payload": "3.0.0-beta.
|
45
|
-
"react": "19.0.0-rc-
|
46
|
-
"react-dom": "19.0.0-rc-
|
39
|
+
"@payloadcms/next": "3.0.0-beta.118",
|
40
|
+
"@payloadcms/translations": "3.0.0-beta.118",
|
41
|
+
"@payloadcms/ui": "3.0.0-beta.118",
|
42
|
+
"jose": "^5.9.6",
|
43
|
+
"next": "^15.0.2-canary.3",
|
44
|
+
"payload": "3.0.0-beta.118",
|
45
|
+
"react": "19.0.0-rc-1631855f-20241023",
|
46
|
+
"react-dom": "19.0.0-rc-1631855f-20241023"
|
47
47
|
},
|
48
48
|
"devDependencies": {
|
49
49
|
"@swc/cli": "^0.4.1-nightly.20240914",
|
50
|
-
"@swc/core": "^1.7.
|
51
|
-
"@types/
|
52
|
-
"@types/
|
53
|
-
"@types/react": "^18.3.11",
|
50
|
+
"@swc/core": "^1.7.39",
|
51
|
+
"@types/node": "^22.7.9",
|
52
|
+
"@types/react": "^18.3.12",
|
54
53
|
"@types/react-dom": "^18.3.1",
|
55
54
|
"rimraf": "^6.0.1",
|
56
|
-
"typescript": "5.7.0-dev.
|
55
|
+
"typescript": "5.7.0-dev.20241024"
|
57
56
|
},
|
58
57
|
"engines": {
|
59
|
-
"node": "^22.
|
58
|
+
"node": "^22.10.0"
|
60
59
|
},
|
61
60
|
"exports": {
|
62
61
|
".": {
|