@@ -80,13 +80,16 @@ function SilentCallback() {
8080}
8181
8282function generateCodeVerifier ( ) {
83- let result = '' ;
84- const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~' ;
85- const charactersLength = characters . length ;
86- for ( let i = 0 ; i < 128 ; i ++ ) {
87- result += characters . charAt ( Math . floor ( Math . random ( ) * charactersLength ) ) ;
88- }
89- return result ;
83+ const array = new Uint8Array ( 96 ) ;
84+ crypto . getRandomValues ( array ) ;
85+ return btoa ( String . fromCharCode ( ...array ) )
86+ . replace ( / = / g, '' ) . replace ( / \+ / g, '-' ) . replace ( / \/ / g, '_' ) ;
87+ }
88+
89+ async function generateCodeChallenge ( verifier ) {
90+ const digest = await crypto . subtle . digest ( 'SHA-256' , new TextEncoder ( ) . encode ( verifier ) ) ;
91+ return btoa ( String . fromCharCode ( ...new Uint8Array ( digest ) ) )
92+ . replace ( / = / g, '' ) . replace ( / \+ / g, '-' ) . replace ( / \/ / g, '_' ) ;
9093}
9194
9295
@@ -111,11 +114,15 @@ function TestIframe() {
111114 const iframe = document . getElementById ( 'silent-auth-iframe' ) ;
112115 if ( iframe && iframe . parentNode ) document . body . removeChild ( iframe ) ;
113116 sessionStorage . removeItem ( 'silent-auth-state' ) ;
117+ sessionStorage . removeItem ( 'silent-auth-verifier' ) ;
114118 } ;
115119
116120 const checkSilentAuth = async ( ) => {
121+ const codeVerifier = generateCodeVerifier ( ) ;
122+ const codeChallenge = await generateCodeChallenge ( codeVerifier ) ;
117123 const state = generateCodeVerifier ( ) ;
118124 sessionStorage . setItem ( 'silent-auth-state' , state ) ;
125+ sessionStorage . setItem ( 'silent-auth-verifier' , codeVerifier ) ;
119126
120127 const done = ( status , authenticated = false ) => {
121128 cleanup ( ) ;
@@ -137,10 +144,26 @@ function TestIframe() {
137144
138145 if ( event . data . code ) {
139146 try {
140- await sdk . oauth . exchange ( event . data . code ) ;
141- done ( 'Authenticated via custom domain' , true ) ;
147+ const verifier = sessionStorage . getItem ( 'silent-auth-verifier' ) ;
148+ sessionStorage . removeItem ( 'silent-auth-verifier' ) ;
149+ const projectId = 'Puse136yK1TiyR4tmmaVToRDQs9icEIl' ;
150+ const customDomain = 'https://auth.reuven.descope.org' ;
151+ const redirectUri = `${ window . location . origin } /silent-callback` ;
152+ const res = await fetch ( `${ customDomain } /v1/auth/oauth/exchange` , {
153+ method : 'POST' ,
154+ headers : { 'Content-Type' : 'application/json' } ,
155+ body : JSON . stringify ( { code : event . data . code , codeVerifier : verifier , clientId : projectId , redirectUri } ) ,
156+ credentials : 'include' ,
157+ } ) ;
158+ if ( res . ok ) {
159+ done ( 'Authenticated via custom domain' , true ) ;
160+ } else {
161+ const body = await res . text ( ) ;
162+ console . log ( 'Silent auth: exchange failed' , res . status , body ) ;
163+ done ( 'No existing session' ) ;
164+ }
142165 } catch ( err ) {
143- console . log ( 'Silent auth: exchange failed ' , err ) ;
166+ console . log ( 'Silent auth: exchange error ' , err ) ;
144167 done ( 'No existing session' ) ;
145168 }
146169 } else {
@@ -165,6 +188,8 @@ function TestIframe() {
165188 `&redirect_uri=${ encodeURIComponent ( redirectUri ) } ` +
166189 `&oidc_error_redirect_uri=${ encodeURIComponent ( redirectUri ) } ` +
167190 `&state=${ state } ` +
191+ `&code_challenge=${ codeChallenge } ` +
192+ `&code_challenge_method=S256` +
168193 `&prompt=none` +
169194 `&scope=openid profile email` ;
170195
0 commit comments