@@ -178,17 +178,25 @@ function step(state::NoAuthentication)::Union{RequestLogin, Failure}
178178 output = IOBuffer ()
179179 # Try device flow first
180180 response = Downloads. request (
181- string (state. server, " / dex/device/code" ),
181+ joinpath (state. server, " dex/device/code" ),
182182 method = " POST" ,
183- input = IOBuffer (" client_id=device&scopes =openid email profile offline_access" ),
183+ input = IOBuffer (" client_id=device&scope =openid email profile offline_access" ),
184184 output = output,
185185 throw = false ,
186- headers = [ " Accept" => " application/json" , " Content-Type" => " application/x-www-form-urlencoded" ] ,
186+ headers = Dict ( " Accept" => " application/json" , " Content-Type" => " application/x-www-form-urlencoded" ) ,
187187 )
188188 if response isa Downloads. Response && response. status == 200
189- body = JSON. parse (String (take! (output)))
190- body[" client_id" ] = " device"
191- return RequestLogin (state. server, " " , body)
189+ body = nothing
190+ try
191+ body = JSON. parse (String (take! (output)))
192+ catch ex
193+ @debug " Request for device code returned: " , body
194+ end
195+
196+ if body != = nothing
197+ body[" client_id" ] = " device"
198+ return RequestLogin (state. server, " " , body)
199+ end
192200 end
193201
194202 challenge = Random. randstring (32 )
@@ -200,7 +208,7 @@ function step(state::NoAuthentication)::Union{RequestLogin, Failure}
200208 throw = false ,
201209 )
202210 if response isa Downloads. Response && response. status == 200
203- return RequestLogin (state. server, challenge, String (take! (output)), false )
211+ return RequestLogin (state. server, challenge, String (take! (output)))
204212 else
205213 return HttpError (response)
206214 end
@@ -246,7 +254,7 @@ function step(state::NeedRefresh)::Union{HasNewToken, NoAuthentication}
246254 is_device = get (state. token, " client_id" , nothing ) == " device"
247255 response = if is_device
248256 Downloads. request (
249- " $ (state. server) / dex/token" ,
257+ joinpath (state. server, " dex/token" ) ,
250258 method = " POST" ,
251259 headers = [" Content-Type" => " application/x-www-form-urlencoded" ],
252260 input = IOBuffer (" grant_type=refresh_token&client_id=device&refresh_token=$refresh_token " ),
@@ -273,6 +281,7 @@ function step(state::NeedRefresh)::Union{HasNewToken, NoAuthentication}
273281 end
274282 if is_device
275283 body[" client_id" ] = " device"
284+ body[" expires" ] = body[" expires_in" ] + Int (floor (time ()))
276285 end
277286 return HasNewToken (state. server, body)
278287 catch err
@@ -344,16 +353,17 @@ end
344353Base. show (io:: IO , s:: RequestLogin ) = print (io, " RequestLogin($(s. server) , <REDACTED>, $(s. response) )" )
345354
346355function step (state:: RequestLogin ):: Union{ClaimToken, Failure}
347- is_device = response isa Dict{String, Any} && get (response, " client_id" , nothing ) == " device"
356+ is_device = state . response isa Dict{String, Any} && get (state . response, " client_id" , nothing ) == " device"
348357 url = if is_device
349358 string (state. response[" verification_uri_complete" ])
350359 else
351360 string (state. server, " /response?" , state. response)
352361 end
353362
354363 success = open_browser (url)
355- if success && state. is_device
356- return ClaimToken (state. server, state. challenge, state. response, expiry= state. response[" expires_in" ])
364+ if success && is_device
365+ # In case of device tokens, timeout for challenge is received in the initial request.
366+ return ClaimToken (state. server, state. challenge, state. response, Inf , time (), state. response[" expires_in" ], 2 , 0 , 10 )
357367 elseif success
358368 return ClaimToken (state. server, state. challenge, state. response)
359369 else # this can only happen for the browser hook
@@ -394,15 +404,16 @@ function step(state::ClaimToken)::Union{ClaimToken, HasNewToken, Failure}
394404 sleep (state. poll_interval)
395405
396406 output = IOBuffer ()
397- is_device = response isa Dict{String, Any} && get (response, " client_id" , nothing ) == " device" )
407+ is_device = state . response isa Dict{String, Any} && get (state . response, " client_id" , nothing ) == " device"
398408 if is_device
409+ output = IOBuffer ()
399410 response = Downloads. request (
400- string (state. server, " / dex/token" ),
411+ joinpath (state. server, " dex/token" ),
401412 method = " POST" ,
402- input = IOBuffer (" client_id=device&scope=openid profile offline_access&grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code= $(state . response[ " device_code " ]) " ),
413+ input = IOBuffer (reqstr ),
403414 output = output,
404415 throw = false ,
405- headers = [ " Accept" => " application/json" , " Content-Type" => " application/x-www-form-urlencoded" ] ,
416+ headers = Dict ( " Accept" => " application/json" , " Content-Type" => " application/x-www-form-urlencoded" ) ,
406417 )
407418 else
408419 data = JSON. json (Dict (
@@ -418,7 +429,7 @@ function step(state::ClaimToken)::Union{ClaimToken, HasNewToken, Failure}
418429 )
419430 end
420431
421- if response isa Downloads. Response && response. status == 200 && state . challenge != = nothing
432+ if response isa Downloads. Response && response. status == 200 && ! is_device
422433 body = try
423434 JSON. parse (String (take! (output)))
424435 catch err
@@ -433,8 +444,11 @@ function step(state::ClaimToken)::Union{ClaimToken, HasNewToken, Failure}
433444 return ClaimToken (state. server, state. challenge, state. response, state. expiry, state. start_time, state. timeout, state. poll_interval, state. failures + 1 , state. max_failures)
434445 end
435446 elseif response isa Downloads. Response && response. status == 200
436- return HasNewToken (state. server, JSON. parse (String (take! (output)))[" access_token" ])
437- elseif response isa Downloads. Response && response. status == 401 && is_device
447+ body = JSON. parse (String (take! (output)))
448+ body[" client_id" ] = " device"
449+ body[" expires" ] = body[" expires_in" ] + Int (floor (time ()))
450+ return HasNewToken (state. server, body)
451+ elseif response isa Downloads. Response && response. status in [401 , 400 ] && is_device
438452 return ClaimToken (state. server, state. challenge, state. response, state. expiry, state. start_time, state. timeout, state. poll_interval, state. failures + 1 , state. max_failures)
439453 else
440454 return HttpError (response)
@@ -487,7 +501,8 @@ is_new_auth_mechanism() =
487501is_token_valid (toml) =
488502 get (toml, " id_token" , nothing ) isa AbstractString &&
489503 get (toml, " refresh_token" , nothing ) isa AbstractString &&
490- get (toml, " refresh_url" , nothing ) isa AbstractString &&
504+ (get (toml, " refresh_url" , nothing ) isa AbstractString ||
505+ get (toml, " client_id" , nothing ) == " device" ) &&
491506 (get (toml, " expires_at" , nothing ) isa Union{Integer, AbstractFloat} ||
492507 get (toml, " expires" , nothing ) isa Union{Integer, AbstractFloat})
493508
0 commit comments