@@ -80,77 +80,84 @@ public static function provideJWTs(): array
8080 [
8181 // JWT with invalid private key signed
8282 'https://pro-1.frontendapi.cloud.corbado.io ' ,
83- self ::generateJWT ('https://pro-1.frontendapi.cloud.corbado.io ' , time () + 100 , time () + 100 , $ invalidPrivateKey ),
83+ self ::generateJWT ('https://pro-1.frontendapi.cloud.corbado.io ' , time () + 100 , time () + 100 , $ invalidPrivateKey, ' RS256 ' ),
8484 false ,
8585 ValidationException::CODE_JWT_INVALID_SIGNATURE
8686 ],
87+ [
88+ // JWT with alg 'none'
89+ 'https://pro-1.frontendapi.cloud.corbado.io ' ,
90+ self ::generateJWT ('https://pro-1.frontendapi.cloud.corbado.io ' , time () + 100 , time () + 100 , $ invalidPrivateKey , 'NONE ' ),
91+ false ,
92+ ValidationException::CODE_JWT_INVALID_DATA
93+ ],
8794 [
8895 // Not before (nfb) in future
8996 'https://pro-1.frontendapi.cloud.corbado.io ' ,
90- self ::generateJWT ('https://pro-1.frontendapi.cloud.corbado.io ' , time () + 100 , time () + 100 , $ privateKey ),
97+ self ::generateJWT ('https://pro-1.frontendapi.cloud.corbado.io ' , time () + 100 , time () + 100 , $ privateKey, ' RS256 ' ),
9198 false ,
9299 ValidationException::CODE_JWT_BEFORE
93100 ],
94101 [
95102 // Expired (exp)
96103 'https://pro-1.frontendapi.cloud.corbado.io ' ,
97- self ::generateJWT ('https://pro-1.frontendapi.cloud.corbado.io ' , time () - 100 , time () - 100 , $ privateKey ),
104+ self ::generateJWT ('https://pro-1.frontendapi.cloud.corbado.io ' , time () - 100 , time () - 100 , $ privateKey, ' RS256 ' ),
98105 false ,
99106 ValidationException::CODE_JWT_EXPIRED
100107 ],
101108 [
102109 // Empty issuer (iss)
103110 'https://pro-1.frontendapi.cloud.corbado.io ' ,
104- self ::generateJWT ('' , time () + 100 , time () - 100 , $ privateKey ),
111+ self ::generateJWT ('' , time () + 100 , time () - 100 , $ privateKey, ' RS256 ' ),
105112 false ,
106113 ValidationException::CODE_JWT_ISSUER_EMPTY
107114 ],
108115 [
109116 // Invalid issuer (iss)
110117 'https://pro-1.frontendapi.cloud.corbado.io ' ,
111- self ::generateJWT ('https://pro-2.frontendapi.cloud.corbado.io ' , time () + 100 , time () - 100 , $ privateKey ),
118+ self ::generateJWT ('https://pro-2.frontendapi.cloud.corbado.io ' , time () + 100 , time () - 100 , $ privateKey, ' RS256 ' ),
112119 false ,
113120 ValidationException::CODE_JWT_ISSUER_MISMATCH
114121 ],
115122 [
116123 // Invalid issuer (iss)
117124 'https://pro-1.frontendapi.corbado.io ' ,
118- self ::generateJWT ('https://pro-2.frontendapi.cloud.corbado.io ' , time () + 100 , time () - 100 , $ privateKey ),
125+ self ::generateJWT ('https://pro-2.frontendapi.cloud.corbado.io ' , time () + 100 , time () - 100 , $ privateKey, ' RS256 ' ),
119126 false ,
120127 ValidationException::CODE_JWT_ISSUER_MISMATCH
121128 ],
122129 [
123130 // Invalid issuer (iss)
124131 'https://pro-1.frontendapi.cloud.corbado.io ' ,
125- self ::generateJWT ('https://pro-2.frontendapi.corbado.io ' , time () + 100 , time () - 100 , $ privateKey ),
132+ self ::generateJWT ('https://pro-2.frontendapi.corbado.io ' , time () + 100 , time () - 100 , $ privateKey, ' RS256 ' ),
126133 false ,
127134 ValidationException::CODE_JWT_ISSUER_MISMATCH
128135 ],
129136 [
130137 // Success with new Frontend API URL
131138 'https://pro-1.frontendapi.cloud.corbado.io ' ,
132- self ::generateJWT ('https://pro-1.frontendapi.cloud.corbado.io ' , time () + 100 , time () - 100 , $ privateKey ),
139+ self ::generateJWT ('https://pro-1.frontendapi.cloud.corbado.io ' , time () + 100 , time () - 100 , $ privateKey, ' RS256 ' ),
133140 true ,
134141 0
135142 ],
136143 [
137144 // Success with old Frontend API URL in JWT
138145 'https://pro-1.frontendapi.cloud.corbado.io ' ,
139- self ::generateJWT ('https://pro-1.frontendapi.corbado.io ' , time () + 100 , time () - 100 , $ privateKey ),
146+ self ::generateJWT ('https://pro-1.frontendapi.corbado.io ' , time () + 100 , time () - 100 , $ privateKey, ' RS256 ' ),
140147 true ,
141148 0
142149 ],
143150 [
144151 // Success with old Frontend API URL in config
145152 'https://pro-1.frontendapi.corbado.io ' ,
146- self ::generateJWT ('https://pro-1.frontendapi.cloud.corbado.io ' , time () + 100 , time () - 100 , $ privateKey ),
153+ self ::generateJWT ('https://pro-1.frontendapi.cloud.corbado.io ' , time () + 100 , time () - 100 , $ privateKey, ' RS256 ' ),
147154 true ,
148155 0
149156 ],
150157 [
151158 // Success with CNAME
152159 'https://auth.acme.com ' ,
153- self ::generateJWT ('https://auth.acme.com ' , time () + 100 , time () - 100 , $ privateKey ),
160+ self ::generateJWT ('https://auth.acme.com ' , time () + 100 , time () - 100 , $ privateKey, ' RS256 ' ),
154161 true ,
155162 0
156163 ]
@@ -304,7 +311,7 @@ public function commit(): bool
304311 /**
305312 * @throws Exception
306313 */
307- private static function generateJWT (string $ iss , int $ exp , int $ nbf , string $ privateKey ): string
314+ private static function generateJWT (string $ iss , int $ exp , int $ nbf , string $ privateKey, string $ alg ): string
308315 {
309316 $ payload = [
310317 'iss ' => $ iss ,
@@ -318,6 +325,23 @@ private static function generateJWT(string $iss, int $exp, int $nbf, string $pri
318325 'orig ' => 'orig ' ,
319326 ];
320327
321- return JWT ::encode ($ payload , $ privateKey , 'RS256 ' , 'kid123 ' );
328+ if ($ alg === 'NONE ' ) {
329+ $ encodedHeader = json_encode (['typ ' => 'JWT ' , 'alg ' => 'none ' ]);
330+ if ($ encodedHeader === false ) {
331+ throw new Exception ('json_encode() failed ' );
332+ }
333+
334+ $ encodedPayload = json_encode ($ payload );
335+ if ($ encodedPayload === false ) {
336+ throw new Exception ('json_encode() failed ' );
337+ }
338+
339+ $ base64UrlHeader = rtrim (strtr (base64_encode ($ encodedHeader ), '+/ ' , '-_ ' ), '= ' );
340+ $ base64UrlPayload = rtrim (strtr (base64_encode ($ encodedPayload ), '+/ ' , '-_ ' ), '= ' );
341+
342+ return $ base64UrlHeader . '. ' . $ base64UrlPayload . '. ' ;
343+ }
344+
345+ return JWT ::encode ($ payload , $ privateKey , $ alg , 'kid123 ' );
322346 }
323347}
0 commit comments