payload-zitadel-plugin 0.3.9 → 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 +57 -25
- package/dist/components/server/LoginButton/index.d.ts +1 -1
- package/dist/components/server/LoginButton/index.d.ts.map +1 -1
- package/dist/components/server/LoginButton/index.js +4 -2
- package/dist/components/server/LoginButton/index.js.map +1 -1
- package/dist/constants.d.ts +34 -10
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +31 -10
- package/dist/constants.js.map +1 -1
- package/dist/handlers/authorize.d.ts +2 -2
- package/dist/handlers/authorize.d.ts.map +1 -1
- package/dist/handlers/authorize.js +18 -26
- package/dist/handlers/authorize.js.map +1 -1
- package/dist/handlers/callback.d.ts +2 -3
- package/dist/handlers/callback.d.ts.map +1 -1
- package/dist/handlers/callback.js +128 -39
- package/dist/handlers/callback.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -51
- package/dist/index.js.map +1 -1
- package/dist/strategy.d.ts +2 -2
- package/dist/strategy.d.ts.map +1 -1
- package/dist/strategy.js +20 -42
- package/dist/strategy.js.map +1 -1
- package/dist/types.d.ts +62 -48
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/redirects.d.ts +5 -0
- package/dist/utils/redirects.d.ts.map +1 -0
- package/dist/utils/redirects.js +16 -0
- package/dist/utils/redirects.js.map +1 -0
- package/dist/utils/state.d.ts +5 -0
- package/dist/utils/state.d.ts.map +1 -0
- package/dist/utils/state.js +7 -0
- package/dist/utils/state.js.map +1 -0
- package/dist/utils/urls.d.ts +5 -0
- package/dist/utils/urls.d.ts.map +1 -0
- package/dist/utils/urls.js +5 -0
- package/dist/utils/urls.js.map +1 -0
- package/package.json +7 -7
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.
|
15
|
+
pnpm add payload-zitadel-plugin@0.4.1
|
16
16
|
```
|
17
17
|
|
18
18
|
## Configuration
|
@@ -23,21 +23,20 @@ Initialize the plugin in Payload Config File. Change the parameters to connect t
|
|
23
23
|
|
24
24
|
```typescript
|
25
25
|
import {buildConfig} from 'payload/config'
|
26
|
-
import {
|
26
|
+
import {zitadelPlugin} from 'payload-zitadel-plugin'
|
27
27
|
|
28
28
|
|
29
29
|
export default buildConfig({
|
30
30
|
...,
|
31
31
|
plugins: [
|
32
|
-
|
32
|
+
zitadelPlugin({
|
33
33
|
// URL of your Zitadel instance
|
34
|
-
issuerUrl: process.env.ZITADEL_URL,
|
34
|
+
issuerUrl: process.env.ZITADEL_URL ?? '',
|
35
35
|
|
36
|
-
// in Zitadel create a new App->Web->PKCE, then copy the Client ID
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
label: 'Zitadel',
|
36
|
+
// in Zitadel create a new App->Web->PKCE in your project, then copy the Client ID
|
37
|
+
// DO NOT FORGET to add '{http://localhost with development mode on or https://your-domain.tld}/api/users/callback'
|
38
|
+
// to the allowed redirect URIs and ALSO to the post logout redirect URIs
|
39
|
+
clientId: process.env.ZITADEL_CLIENT_ID ?? '',
|
41
40
|
|
42
41
|
// change field names, field labels and alse hide them if wanted
|
43
42
|
/*
|
@@ -52,23 +51,40 @@ export default buildConfig({
|
|
52
51
|
// set the name of the CustomStrategy in PayloadCMS - usually not necessary
|
53
52
|
// strategyName: 'zitadel'
|
54
53
|
|
55
|
-
|
56
|
-
|
54
|
+
/*
|
55
|
+
avatar: {
|
56
|
+
// set to true if you do not want to use the Zitadel Profile Picture as the Avatar
|
57
|
+
disable: true
|
58
|
+
}
|
59
|
+
*/
|
60
|
+
|
61
|
+
|
62
|
+
/*
|
63
|
+
loginButton: {
|
64
|
+
// set to true if you want to use your own custom login button
|
65
|
+
disable: true,
|
66
|
+
|
67
|
+
// interpolation text for the Login Button - "sign in with ..."
|
68
|
+
label: 'Zitadel'
|
69
|
+
}
|
70
|
+
*/
|
57
71
|
|
58
|
-
//
|
59
|
-
//
|
72
|
+
// if you want to manually control what happens after a successful login
|
73
|
+
// afterLogin: (req) => NextResponse.redirect('...')
|
60
74
|
|
61
|
-
// if you want to manually control what
|
62
|
-
//
|
63
|
-
// onSuccess: (state) => NextResponse.redirect([serverURL, state.get('redirect')].join(''))
|
75
|
+
// if you want to manually control what happens after a successful logout
|
76
|
+
// afterLogout: (req) => NextResponse.redirect('...')
|
64
77
|
|
65
|
-
// following properties are only needed if you want to authenticate clients for the API
|
66
|
-
// if
|
67
|
-
// in Zitadel
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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 visiting the CMS via a browser you can ignore all of them
|
80
|
+
// otherwise create in Zitadel a new App->API->JWT and copy the Client ID, Key ID and the Key itself
|
81
|
+
/*
|
82
|
+
api: {
|
83
|
+
clientId: process.env.ZITADEL_API_CLIENT_ID ?? ''
|
84
|
+
keyId: process.env.ZITADEL_API_KEY_ID ?? ''
|
85
|
+
key: process.env.ZITADEL_API_KEY ?? ''
|
86
|
+
}
|
87
|
+
*/
|
72
88
|
})
|
73
89
|
],
|
74
90
|
...
|
@@ -136,16 +152,32 @@ const nextConfig = {
|
|
136
152
|
]
|
137
153
|
},
|
138
154
|
|
139
|
-
// optional: enable auto-redirect to Zitadel login page if not logged in
|
140
155
|
async redirects() {
|
141
156
|
return [
|
157
|
+
// for proper logout
|
142
158
|
{
|
143
|
-
source: '/:path((
|
159
|
+
source: '/:path((?!api).*)',
|
160
|
+
destination: '/api/users/end_session?redirect=/:path*',
|
161
|
+
has: [
|
162
|
+
{
|
163
|
+
type: 'cookie',
|
164
|
+
key: 'zitadel_logout'
|
165
|
+
}
|
166
|
+
],
|
167
|
+
permanent: false
|
168
|
+
},
|
169
|
+
// optional: enable auto-redirect to Zitadel login page if not logged in
|
170
|
+
{
|
171
|
+
source: '/:path((?!admin\/logout)(?:admin|profile).*)',
|
144
172
|
destination: '/api/users/authorize?redirect=/:path*',
|
145
173
|
missing: [
|
146
174
|
{
|
147
175
|
type: 'cookie',
|
148
176
|
key: 'zitadel_id_token'
|
177
|
+
},
|
178
|
+
{
|
179
|
+
type: 'cookie',
|
180
|
+
key: 'zitadel_logout'
|
149
181
|
}
|
150
182
|
],
|
151
183
|
permanent: false
|
@@ -1,4 +1,4 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import type { ZitadelLoginButtonProps } from '../../../types.js';
|
3
|
-
export declare const LoginButton: ({
|
3
|
+
export declare const LoginButton: ({ payload: { config }, i18n, label }: ZitadelLoginButtonProps) => Promise<React.JSX.Element>;
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/server/LoginButton/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/server/LoginButton/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,mBAAmB,CAAA;AAG9D,eAAO,MAAM,WAAW,yCAA4C,uBAAuB,+BAKjF,CAAA"}
|
@@ -1,13 +1,15 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { Button } from '@payloadcms/ui';
|
3
|
-
|
3
|
+
import { ROUTES } from '../../../constants.js';
|
4
|
+
import { getAuthBaseURL } from '../../../utils/index.js';
|
5
|
+
export const LoginButton = async ({ payload: { config }, i18n, label })=>/*#__PURE__*/ React.createElement("div", {
|
4
6
|
style: {
|
5
7
|
display: 'flex',
|
6
8
|
justifyContent: 'center'
|
7
9
|
}
|
8
10
|
}, /*#__PURE__*/ React.createElement(Button, {
|
9
11
|
el: "anchor",
|
10
|
-
url:
|
12
|
+
url: getAuthBaseURL(config) + ROUTES.authorize
|
11
13
|
}, i18n.t('zitadelPlugin:signIn', {
|
12
14
|
label
|
13
15
|
})));
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/server/LoginButton/index.tsx"],"sourcesContent":["import React from 'react'\nimport {Button} from '@payloadcms/ui'\nimport type {ZitadelLoginButtonProps} from '../../../types.js'\n\nexport const LoginButton = async ({
|
1
|
+
{"version":3,"sources":["../../../../src/components/server/LoginButton/index.tsx"],"sourcesContent":["import React from 'react'\nimport {Button} from '@payloadcms/ui'\nimport {ROUTES} from '../../../constants.js'\nimport type {ZitadelLoginButtonProps} from '../../../types.js'\nimport {getAuthBaseURL} from '../../../utils/index.js'\n\nexport const LoginButton = async ({payload: {config}, i18n, label}: ZitadelLoginButtonProps) =>\n <div style={{display: 'flex', justifyContent: 'center'}}>\n <Button el=\"anchor\" url={getAuthBaseURL(config) + ROUTES.authorize}>\n {i18n.t('zitadelPlugin:signIn', {label})}\n </Button>\n </div>"],"names":["React","Button","ROUTES","getAuthBaseURL","LoginButton","payload","config","i18n","label","div","style","display","justifyContent","el","url","authorize","t"],"mappings":"AAAA,OAAOA,WAAW,QAAO;AACzB,SAAQC,MAAM,QAAO,iBAAgB;AACrC,SAAQC,MAAM,QAAO,wBAAuB;AAE5C,SAAQC,cAAc,QAAO,0BAAyB;AAEtD,OAAO,MAAMC,cAAc,OAAO,EAACC,SAAS,EAACC,MAAM,EAAC,EAAEC,IAAI,EAAEC,KAAK,EAA0B,iBACvF,oBAACC;QAAIC,OAAO;YAACC,SAAS;YAAQC,gBAAgB;QAAQ;qBAClD,oBAACX;QAAOY,IAAG;QAASC,KAAKX,eAAeG,UAAUJ,OAAOa,SAAS;OAC7DR,KAAKS,CAAC,CAAC,wBAAwB;QAACR;IAAK,KAExC"}
|
package/dist/constants.d.ts
CHANGED
@@ -1,8 +1,32 @@
|
|
1
|
+
export declare const AUTHORIZE_QUERY: {
|
2
|
+
response_type: string;
|
3
|
+
scope: string;
|
4
|
+
code_challenge_method: string;
|
5
|
+
};
|
1
6
|
export declare const COMPONENTS_PATH = "payload-zitadel-plugin/components";
|
2
7
|
export declare const COOKIES: {
|
3
|
-
pkce:
|
4
|
-
|
5
|
-
|
8
|
+
pkce: {
|
9
|
+
httpOnly: true;
|
10
|
+
path: string;
|
11
|
+
sameSite: "lax";
|
12
|
+
secure: boolean;
|
13
|
+
name: string;
|
14
|
+
};
|
15
|
+
idToken: {
|
16
|
+
httpOnly: true;
|
17
|
+
path: string;
|
18
|
+
sameSite: "lax";
|
19
|
+
secure: boolean;
|
20
|
+
name: string;
|
21
|
+
};
|
22
|
+
logout: {
|
23
|
+
httpOnly: true;
|
24
|
+
path: string;
|
25
|
+
sameSite: "lax";
|
26
|
+
secure: boolean;
|
27
|
+
name: string;
|
28
|
+
value: string;
|
29
|
+
};
|
6
30
|
};
|
7
31
|
export declare const DEFAULT_CONFIG: {
|
8
32
|
fields: {
|
@@ -64,16 +88,16 @@ export declare const DEFAULT_CONFIG: {
|
|
64
88
|
strategyName: string;
|
65
89
|
label: string;
|
66
90
|
};
|
67
|
-
export declare const
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
apiKey: string;
|
91
|
+
export declare const ENDPOINT_PATHS: {
|
92
|
+
authorize: string;
|
93
|
+
introspect: string;
|
94
|
+
token: string;
|
95
|
+
end_session: string;
|
73
96
|
};
|
97
|
+
export declare const ROLES_KEY = "urn:zitadel:iam:org:project:roles";
|
74
98
|
export declare const ROUTES: {
|
75
99
|
authorize: string;
|
76
100
|
callback: string;
|
77
|
-
|
101
|
+
end_session: string;
|
78
102
|
};
|
79
103
|
//# sourceMappingURL=constants.d.ts.map
|
package/dist/constants.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,eAAe;;;;CAI3B,CAAA;AAED,eAAO,MAAM,eAAe,sCAAsC,CAAA;AASlE,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;CAcnB,CAAA;AAED,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsC1B,CAAA;AAED,eAAO,MAAM,cAAc;;;;;CAK1B,CAAA;AAED,eAAO,MAAM,SAAS,sCAAsC,CAAA;AAE5D,eAAO,MAAM,MAAM;;;;CAIlB,CAAA"}
|
package/dist/constants.js
CHANGED
@@ -1,8 +1,29 @@
|
|
1
|
+
export const AUTHORIZE_QUERY = {
|
2
|
+
response_type: 'code',
|
3
|
+
scope: 'openid email profile',
|
4
|
+
code_challenge_method: 'S256'
|
5
|
+
};
|
1
6
|
export const COMPONENTS_PATH = 'payload-zitadel-plugin/components';
|
7
|
+
const COOKIE_CONFIG = {
|
8
|
+
httpOnly: true,
|
9
|
+
path: '/',
|
10
|
+
sameSite: 'lax',
|
11
|
+
secure: process.env.NODE_ENV == 'production'
|
12
|
+
};
|
2
13
|
export const COOKIES = {
|
3
|
-
pkce:
|
4
|
-
|
5
|
-
|
14
|
+
pkce: {
|
15
|
+
name: 'zitadel_pkce_code_verifier',
|
16
|
+
...COOKIE_CONFIG
|
17
|
+
},
|
18
|
+
idToken: {
|
19
|
+
name: 'zitadel_id_token',
|
20
|
+
...COOKIE_CONFIG
|
21
|
+
},
|
22
|
+
logout: {
|
23
|
+
name: 'zitadel_logout',
|
24
|
+
value: 'true',
|
25
|
+
...COOKIE_CONFIG
|
26
|
+
}
|
6
27
|
};
|
7
28
|
export const DEFAULT_CONFIG = {
|
8
29
|
fields: {
|
@@ -64,17 +85,17 @@ export const DEFAULT_CONFIG = {
|
|
64
85
|
strategyName: 'zitadel',
|
65
86
|
label: 'Zitadel'
|
66
87
|
};
|
67
|
-
export const
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
apiKey: 'ZITADEL-PLUGIN: API ENABLED, BUT API-KEY IS EMPTY'
|
88
|
+
export const ENDPOINT_PATHS = {
|
89
|
+
authorize: '/oauth/v2/authorize',
|
90
|
+
introspect: '/oauth/v2/introspect',
|
91
|
+
token: '/oauth/v2/token',
|
92
|
+
end_session: '/oidc/v1/end_session'
|
73
93
|
};
|
94
|
+
export const ROLES_KEY = 'urn:zitadel:iam:org:project:roles';
|
74
95
|
export const ROUTES = {
|
75
96
|
authorize: '/authorize',
|
76
97
|
callback: '/callback',
|
77
|
-
|
98
|
+
end_session: '/end_session'
|
78
99
|
};
|
79
100
|
|
80
101
|
//# sourceMappingURL=constants.js.map
|
package/dist/constants.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/constants.ts"],"sourcesContent":["import type {ZitadelFieldsConfig} from './types.js'\n\nexport const COMPONENTS_PATH = 'payload-zitadel-plugin/components'\n\nexport const COOKIES = {\n pkce: 'zitadel_pkce_code_verifier',\n idToken: 'zitadel_id_token',\n
|
1
|
+
{"version":3,"sources":["../src/constants.ts"],"sourcesContent":["import {ResponseCookie} from 'next/dist/compiled/@edge-runtime/cookies/index.js'\nimport type {ZitadelFieldsConfig} from './types.js'\n\nexport const AUTHORIZE_QUERY = {\n response_type: 'code',\n scope: 'openid email profile',\n code_challenge_method: 'S256'\n}\n\nexport const COMPONENTS_PATH = 'payload-zitadel-plugin/components'\n\nconst COOKIE_CONFIG = {\n httpOnly: true,\n path: '/',\n sameSite: 'lax',\n secure: process.env.NODE_ENV == 'production'\n} satisfies Pick<ResponseCookie, 'httpOnly' | 'path' | 'sameSite' | 'secure'>\n\nexport const COOKIES = {\n pkce: {\n name: 'zitadel_pkce_code_verifier',\n ...COOKIE_CONFIG\n } satisfies Omit<ResponseCookie, 'value'>,\n idToken: {\n name: 'zitadel_id_token',\n ...COOKIE_CONFIG\n } satisfies Omit<ResponseCookie, 'value'>,\n logout: {\n name: 'zitadel_logout',\n value: 'true',\n ...COOKIE_CONFIG\n } satisfies ResponseCookie\n}\n\nexport const DEFAULT_CONFIG = {\n fields: {\n id: {\n name: 'idp_id',\n label: {\n de: 'Identifikation im System des Identitätsanbieters',\n en: 'Identifier in the system of the Identity Provider'\n }\n },\n name: {\n name: 'name',\n label: {de: 'Name', en: 'Name'}\n },\n email: {\n name: 'email',\n label: {de: 'E-Mail', en: 'Email'}\n },\n image: {\n name: 'image',\n label: {de: 'Profilbild-URL', en: 'Profile picture URL'}\n },\n roles: {\n name: 'roles',\n label: {de: 'Rollen', en: 'Roles'},\n labels: {\n singular: {de: 'Rolle', en: 'Role'},\n plural: {de: 'Rollen', en: 'Roles'}\n }\n },\n roleFields: {\n name: {\n name: 'name',\n label: {de: 'Name', en: 'Name'}\n }\n }\n } satisfies ZitadelFieldsConfig,\n strategyName: 'zitadel',\n label: 'Zitadel'\n}\n\nexport const ENDPOINT_PATHS = {\n authorize: '/oauth/v2/authorize',\n introspect: '/oauth/v2/introspect',\n token: '/oauth/v2/token',\n end_session: '/oidc/v1/end_session'\n}\n\nexport const ROLES_KEY = 'urn:zitadel:iam:org:project:roles'\n\nexport const ROUTES = {\n authorize: '/authorize',\n callback: '/callback',\n end_session: '/end_session'\n}\n\n"],"names":["AUTHORIZE_QUERY","response_type","scope","code_challenge_method","COMPONENTS_PATH","COOKIE_CONFIG","httpOnly","path","sameSite","secure","process","env","NODE_ENV","COOKIES","pkce","name","idToken","logout","value","DEFAULT_CONFIG","fields","id","label","de","en","email","image","roles","labels","singular","plural","roleFields","strategyName","ENDPOINT_PATHS","authorize","introspect","token","end_session","ROLES_KEY","ROUTES","callback"],"mappings":"AAGA,OAAO,MAAMA,kBAAkB;IAC3BC,eAAe;IACfC,OAAO;IACPC,uBAAuB;AAC3B,EAAC;AAED,OAAO,MAAMC,kBAAkB,oCAAmC;AAElE,MAAMC,gBAAgB;IAClBC,UAAU;IACVC,MAAM;IACNC,UAAU;IACVC,QAAQC,QAAQC,GAAG,CAACC,QAAQ,IAAI;AACpC;AAEA,OAAO,MAAMC,UAAU;IACnBC,MAAM;QACFC,MAAM;QACN,GAAGV,aAAa;IACpB;IACAW,SAAS;QACLD,MAAM;QACN,GAAGV,aAAa;IACpB;IACAY,QAAQ;QACJF,MAAM;QACNG,OAAO;QACP,GAAGb,aAAa;IACpB;AACJ,EAAC;AAED,OAAO,MAAMc,iBAAiB;IAC1BC,QAAQ;QACJC,IAAI;YACAN,MAAM;YACNO,OAAO;gBACHC,IAAI;gBACJC,IAAI;YACR;QACJ;QACAT,MAAM;YACFA,MAAM;YACNO,OAAO;gBAACC,IAAI;gBAAQC,IAAI;YAAM;QAClC;QACAC,OAAO;YACHV,MAAM;YACNO,OAAO;gBAACC,IAAI;gBAAUC,IAAI;YAAO;QACrC;QACAE,OAAO;YACHX,MAAM;YACNO,OAAO;gBAACC,IAAI;gBAAkBC,IAAI;YAAqB;QAC3D;QACAG,OAAO;YACHZ,MAAM;YACNO,OAAO;gBAACC,IAAI;gBAAUC,IAAI;YAAO;YACjCI,QAAQ;gBACJC,UAAU;oBAACN,IAAI;oBAASC,IAAI;gBAAM;gBAClCM,QAAQ;oBAACP,IAAI;oBAAUC,IAAI;gBAAO;YACtC;QACJ;QACAO,YAAY;YACRhB,MAAM;gBACFA,MAAM;gBACNO,OAAO;oBAACC,IAAI;oBAAQC,IAAI;gBAAM;YAClC;QACJ;IACJ;IACAQ,cAAc;IACdV,OAAO;AACX,EAAC;AAED,OAAO,MAAMW,iBAAiB;IAC1BC,WAAW;IACXC,YAAY;IACZC,OAAO;IACPC,aAAa;AACjB,EAAC;AAED,OAAO,MAAMC,YAAY,oCAAmC;AAE5D,OAAO,MAAMC,SAAS;IAClBL,WAAW;IACXM,UAAU;IACVH,aAAa;AACjB,EAAC"}
|
@@ -1,3 +1,3 @@
|
|
1
|
-
import
|
2
|
-
export declare const authorize:
|
1
|
+
import { ZitadelBaseHandler } from '../types.js';
|
2
|
+
export declare const authorize: ZitadelBaseHandler;
|
3
3
|
//# sourceMappingURL=authorize.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../src/handlers/authorize.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../src/handlers/authorize.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,kBAAkB,EAAC,MAAM,aAAa,CAAA;AAG9C,eAAO,MAAM,SAAS,EAAE,kBAgBvB,CAAA"}
|
@@ -1,30 +1,22 @@
|
|
1
|
-
import process from 'node:process';
|
2
1
|
import { cookies } from 'next/headers.js';
|
3
|
-
import { NextResponse } from 'next/server.js';
|
4
2
|
import { COOKIES } from '../constants.js';
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
scope: 'openid email profile',
|
24
|
-
state: btoa(searchParams.toString()),
|
25
|
-
code_challenge,
|
26
|
-
code_challenge_method: 'S256'
|
27
|
-
})}`);
|
28
|
-
};
|
3
|
+
import { requestRedirect } from '../utils/index.js';
|
4
|
+
export const authorize = ({ issuerURL, clientId })=>async (req)=>{
|
5
|
+
const codeVerifier = Buffer.from(crypto.getRandomValues(new Uint8Array(24))).toString('base64url');
|
6
|
+
const codeChallenge = Buffer.from(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(codeVerifier))).toString('base64url');
|
7
|
+
const cookieStore = await cookies();
|
8
|
+
cookieStore.set({
|
9
|
+
...COOKIES.pkce,
|
10
|
+
value: codeVerifier,
|
11
|
+
maxAge: 300
|
12
|
+
});
|
13
|
+
return requestRedirect({
|
14
|
+
req,
|
15
|
+
issuerURL,
|
16
|
+
clientId,
|
17
|
+
invokedBy: 'authorize',
|
18
|
+
codeChallenge
|
19
|
+
});
|
20
|
+
};
|
29
21
|
|
30
22
|
//# sourceMappingURL=authorize.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../src/handlers/authorize.ts"],"sourcesContent":["import
|
1
|
+
{"version":3,"sources":["../../src/handlers/authorize.ts"],"sourcesContent":["import {cookies} from 'next/headers.js'\nimport {COOKIES} from '../constants.js'\nimport {ZitadelBaseHandler} from '../types.js'\nimport {requestRedirect} from '../utils/index.js'\n\nexport const authorize: ZitadelBaseHandler = ({issuerURL, clientId}) => async (req) => {\n\n const codeVerifier = Buffer.from(crypto.getRandomValues(new Uint8Array(24))).toString('base64url')\n\n const codeChallenge = Buffer.from(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(codeVerifier))).toString('base64url')\n\n const cookieStore = await cookies()\n\n cookieStore.set({\n ...COOKIES.pkce,\n value: codeVerifier,\n maxAge: 300\n })\n\n return requestRedirect({req, issuerURL, clientId, invokedBy: 'authorize', codeChallenge})\n\n}\n"],"names":["cookies","COOKIES","requestRedirect","authorize","issuerURL","clientId","req","codeVerifier","Buffer","from","crypto","getRandomValues","Uint8Array","toString","codeChallenge","subtle","digest","TextEncoder","encode","cookieStore","set","pkce","value","maxAge","invokedBy"],"mappings":"AAAA,SAAQA,OAAO,QAAO,kBAAiB;AACvC,SAAQC,OAAO,QAAO,kBAAiB;AAEvC,SAAQC,eAAe,QAAO,oBAAmB;AAEjD,OAAO,MAAMC,YAAgC,CAAC,EAACC,SAAS,EAAEC,QAAQ,EAAC,GAAK,OAAOC;QAE3E,MAAMC,eAAeC,OAAOC,IAAI,CAACC,OAAOC,eAAe,CAAC,IAAIC,WAAW,MAAMC,QAAQ,CAAC;QAEtF,MAAMC,gBAAgBN,OAAOC,IAAI,CAAC,MAAMC,OAAOK,MAAM,CAACC,MAAM,CAAC,WAAW,IAAIC,cAAcC,MAAM,CAACX,gBAAgBM,QAAQ,CAAC;QAE1H,MAAMM,cAAc,MAAMnB;QAE1BmB,YAAYC,GAAG,CAAC;YACZ,GAAGnB,QAAQoB,IAAI;YACfC,OAAOf;YACPgB,QAAQ;QACZ;QAEA,OAAOrB,gBAAgB;YAACI;YAAKF;YAAWC;YAAUmB,WAAW;YAAaV;QAAa;IAE3F,EAAC"}
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import
|
2
|
-
|
3
|
-
export declare const callback: (onSuccess: ZitadelOnSuccess) => PayloadHandler;
|
1
|
+
import { ZitadelCallbackHandler } from '../types.js';
|
2
|
+
export declare const callback: ZitadelCallbackHandler;
|
4
3
|
//# sourceMappingURL=callback.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["../../src/handlers/callback.ts"],"names":[],"mappings":"AAGA,OAAO,
|
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"}
|
@@ -1,53 +1,142 @@
|
|
1
|
-
import process from 'node:process';
|
2
1
|
import { SignJWT, decodeJwt } from 'jose';
|
3
2
|
import { cookies } from 'next/headers.js';
|
4
|
-
import { COOKIES } from '../constants.js';
|
5
|
-
|
6
|
-
|
3
|
+
import { COOKIES, ENDPOINT_PATHS, ROLES_KEY, ROUTES } from '../constants.js';
|
4
|
+
import { getAuthBaseURL, getAuthSlug, getState } from '../utils/index.js';
|
5
|
+
export const callback = ({ issuerURL, clientId, fields, afterLogin, afterLogout })=>async (req)=>{
|
6
|
+
const { payload, query } = req;
|
7
|
+
const { config, secret } = payload;
|
8
|
+
const { code } = query;
|
9
|
+
const state = getState(req);
|
7
10
|
const cookieStore = await cookies();
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
11
|
+
if (state.invokedBy == 'end_session') {
|
12
|
+
[
|
13
|
+
COOKIES.logout,
|
14
|
+
COOKIES.idToken
|
15
|
+
].forEach((cookie)=>cookieStore.delete(cookie));
|
16
|
+
return afterLogout(req);
|
17
|
+
}
|
18
|
+
const codeVerifier = cookieStore.get(COOKIES.pkce.name)?.value;
|
19
|
+
if (!code) {
|
20
|
+
return Response.json({
|
21
|
+
status: 'error',
|
22
|
+
message: 'no code provided to verify'
|
23
|
+
});
|
24
|
+
}
|
25
|
+
if (!codeVerifier) {
|
26
|
+
return Response.json({
|
27
|
+
status: 'error',
|
28
|
+
message: 'code verifier not found (associated http-only cookie is empty)'
|
29
|
+
});
|
30
|
+
}
|
31
|
+
const tokenQueryData = {
|
32
|
+
grant_type: 'authorization_code',
|
33
|
+
code,
|
34
|
+
redirect_uri: getAuthBaseURL(config) + ROUTES.callback,
|
35
|
+
client_id: clientId,
|
36
|
+
code_verifier: codeVerifier
|
37
|
+
};
|
38
|
+
const tokenEndpoint = issuerURL + ENDPOINT_PATHS.token;
|
39
|
+
const tokenResponse = await fetch(new URL(tokenEndpoint), {
|
40
|
+
method: 'POST',
|
41
|
+
body: new URLSearchParams(tokenQueryData)
|
42
|
+
});
|
43
|
+
if (!tokenResponse.ok) {
|
44
|
+
return Response.json({
|
45
|
+
status: 'error',
|
46
|
+
message: 'error while communicating with token endpoint',
|
47
|
+
details: {
|
48
|
+
tokenEndpoint,
|
49
|
+
tokenQuery: tokenQueryData,
|
50
|
+
tokenResponseCode: `${tokenResponse.status} - ${tokenResponse.statusText}`
|
51
|
+
}
|
52
|
+
});
|
53
|
+
}
|
54
|
+
const tokenJson = await tokenResponse.json();
|
55
|
+
const { id_token: idToken } = tokenJson;
|
56
|
+
if (!idToken) {
|
57
|
+
return Response.json({
|
58
|
+
status: 'error',
|
59
|
+
message: 'token could not be retrieved from this response',
|
60
|
+
details: {
|
61
|
+
responseData: tokenJson
|
36
62
|
}
|
37
|
-
|
38
|
-
|
39
|
-
|
63
|
+
});
|
64
|
+
}
|
65
|
+
let decodedIdToken;
|
66
|
+
try {
|
67
|
+
decodedIdToken = decodeJwt(idToken);
|
68
|
+
} catch (e) {
|
69
|
+
return Response.json({
|
70
|
+
status: 'error',
|
71
|
+
message: `error during decoding: ${JSON.stringify(e)}`,
|
72
|
+
details: {
|
73
|
+
idToken
|
74
|
+
}
|
75
|
+
});
|
76
|
+
}
|
77
|
+
const idpId = decodedIdToken.sub;
|
78
|
+
const userData = {
|
79
|
+
[fields.name.name]: decodedIdToken.name,
|
80
|
+
[fields.email.name]: decodedIdToken.email,
|
81
|
+
[fields.image.name]: decodedIdToken.picture,
|
82
|
+
[fields.roles.name]: Object.keys(decodedIdToken[ROLES_KEY] ?? {}).map((key)=>({
|
83
|
+
[fields.roleFields.name.name]: key
|
84
|
+
}))
|
85
|
+
};
|
86
|
+
if (!idpId) {
|
87
|
+
return Response.json({
|
88
|
+
status: 'error',
|
89
|
+
message: 'token is not complete (id not found)',
|
90
|
+
details: {
|
91
|
+
idToken,
|
92
|
+
decodedIdToken,
|
93
|
+
idpId
|
94
|
+
}
|
95
|
+
});
|
96
|
+
}
|
97
|
+
try {
|
98
|
+
const authSlug = getAuthSlug(config);
|
99
|
+
const { docs, totalDocs } = await payload.find({
|
100
|
+
collection: authSlug,
|
101
|
+
where: {
|
102
|
+
[fields.id.name]: {
|
103
|
+
equals: idpId
|
104
|
+
}
|
105
|
+
}
|
106
|
+
});
|
107
|
+
if (totalDocs) {
|
108
|
+
await payload.update({
|
109
|
+
collection: authSlug,
|
110
|
+
id: docs[0].id,
|
111
|
+
data: userData
|
112
|
+
});
|
113
|
+
} else {
|
114
|
+
await payload.create({
|
115
|
+
collection: authSlug,
|
116
|
+
data: {
|
117
|
+
[fields.id.name]: idpId,
|
118
|
+
...userData
|
119
|
+
}
|
40
120
|
});
|
41
121
|
}
|
122
|
+
} catch (e) {
|
42
123
|
return Response.json({
|
43
124
|
status: 'error',
|
44
|
-
message:
|
125
|
+
message: `error while creating/updating user: ${JSON.stringify(e)}`,
|
126
|
+
details: {
|
127
|
+
idpId
|
128
|
+
}
|
45
129
|
});
|
46
130
|
}
|
47
|
-
|
48
|
-
|
49
|
-
|
131
|
+
cookieStore.delete(COOKIES.pkce);
|
132
|
+
cookieStore.set({
|
133
|
+
...COOKIES.idToken,
|
134
|
+
value: await new SignJWT(decodedIdToken).setProtectedHeader({
|
135
|
+
alg: 'HS256'
|
136
|
+
}).setIssuedAt().sign(new TextEncoder().encode(secret)),
|
137
|
+
maxAge: 900
|
50
138
|
});
|
139
|
+
return afterLogin(req);
|
51
140
|
};
|
52
141
|
|
53
142
|
//# sourceMappingURL=callback.js.map
|