@@ -2,7 +2,8 @@ import type { H3Event } from 'h3'
22import { eventHandler , getQuery , sendRedirect } from 'h3'
33import { withQuery } from 'ufo'
44import { defu } from 'defu'
5- import { handleMissingConfiguration , handleAccessTokenErrorResponse , getOAuthRedirectURL , requestAccessToken } from '../utils'
5+ import type { RequestAccessTokenOptions } from '../utils'
6+ import { handleMissingConfiguration , handleAccessTokenErrorResponse , getOAuthRedirectURL , requestAccessToken , handleState , handlePkceVerifier , handleInvalidState } from '../utils'
67import { useRuntimeConfig , createError } from '#imports'
78import type { OAuthConfig } from '#auth-utils'
89
@@ -48,7 +49,7 @@ export function defineOAuthZitadelEventHandler({ config, onSuccess, onError }: O
4849 authorizationParams : { } ,
4950 } ) as OAuthZitadelConfig
5051
51- const query = getQuery < { code ?: string , error ?: string } > ( event )
52+ const query = getQuery < { code ?: string , state ?: string , error ?: string } > ( event )
5253
5354 if ( query . error ) {
5455 const error = createError ( {
@@ -60,14 +61,18 @@ export function defineOAuthZitadelEventHandler({ config, onSuccess, onError }: O
6061 return onError ( event , error )
6162 }
6263
63- if ( ! config . clientId || ! config . clientSecret || ! config . domain ) {
64- return handleMissingConfiguration ( event , 'zitadel' , [ 'clientId' , 'clientSecret' , 'issuerUrl '] , onError )
64+ if ( ! config . clientId || ! config . domain ) {
65+ return handleMissingConfiguration ( event , 'zitadel' , [ 'clientId' , 'domain ' ] , onError )
6566 }
6667
6768 const authorizationURL = `https://${ config . domain } /oauth/v2/authorize`
6869 const tokenURL = `https://${ config . domain } /oauth/v2/token`
6970 const redirectURL = config . redirectURL || getOAuthRedirectURL ( event )
7071
72+ // Create pkce verifier
73+ const verifier = await handlePkceVerifier ( event )
74+ const state = await handleState ( event )
75+
7176 if ( ! query . code ) {
7277 config . scope = config . scope || [ 'openid' ]
7378 // Redirect to Zitadel OAuth page
@@ -79,23 +84,37 @@ export function defineOAuthZitadelEventHandler({ config, onSuccess, onError }: O
7984 client_id : config . clientId ,
8085 redirect_uri : redirectURL ,
8186 scope : config . scope . join ( ' ' ) ,
87+ state,
88+ code_challenge : verifier . code_challenge ,
89+ code_challenge_method : verifier . code_challenge_method ,
8290 ...config . authorizationParams ,
8391 } ) ,
8492 )
8593 }
8694
87- const tokens = await requestAccessToken ( tokenURL , {
88- headers : {
89- 'Authorization' : `Basic ${ Buffer . from ( ` ${ config . clientId } : ${ config . clientSecret } ` ) . toString ( 'base64' ) } ` ,
90- 'Content-Type' : 'application/x-www-form-urlencoded' ,
91- } ,
95+ if ( query . state !== state ) {
96+ return handleInvalidState ( event , 'zitadel' , onError )
97+ }
98+
99+ const request : RequestAccessTokenOptions = {
92100 body : {
93101 grant_type : 'authorization_code' ,
94102 client_id : config . clientId ,
95103 redirect_uri : redirectURL ,
96104 code : query . code ,
105+ code_verifier : verifier . code_verifier ,
97106 } ,
98- } )
107+ }
108+
109+ if ( config . clientSecret ) {
110+ const basicAuthorization = Buffer . from ( `${ config . clientId } :${ config . clientSecret } ` ) . toString ( 'base64' )
111+ request . headers = {
112+ 'Authorization' : `Basic ${ basicAuthorization } ` ,
113+ 'Content-Type' : 'application/x-www-form-urlencoded' ,
114+ }
115+ }
116+
117+ const tokens = await requestAccessToken ( tokenURL , request )
99118
100119 if ( tokens . error ) {
101120 return handleAccessTokenErrorResponse ( event , 'zitadel' , tokens , onError )
0 commit comments