Implementation
Future<void> pollForCompletion(DeviceCodeChallenge challenge) async {
final deadline = DateTime.now().add(_pollTimeout);
while (DateTime.now().isBefore(deadline)) {
await Future.delayed(Duration(seconds: challenge.intervalSeconds));
try {
final response = await _dio.post(
'$_issuer/api/accounts/deviceauth/token',
options: Options(
headers: {'content-type': 'application/json'},
validateStatus: (status) => status != null && status < 500,
),
data: {
'device_auth_id': challenge.deviceAuthId,
'user_code': challenge.userCode,
},
);
debugPrint('[OpenAiAuth] Poll status=${response.statusCode}');
if (response.statusCode == 403 || response.statusCode == 404) {
continue;
}
if (response.statusCode != null &&
response.statusCode! >= 200 &&
response.statusCode! < 300) {
final data = response.data as Map<String, dynamic>;
debugPrint('[OpenAiAuth] Poll success keys=${data.keys.toList()}');
final authCode = data['authorization_code'] as String;
final codeVerifier = data['code_verifier'] as String;
await _exchangeCodeForTokens(authCode, codeVerifier);
return;
}
throw Exception('Device auth poll failed: HTTP ${response.statusCode}');
} on DioException catch (e) {
if (e.response?.statusCode == 403 || e.response?.statusCode == 404) {
continue;
}
rethrow;
}
}
throw Exception('Device code sign-in timed out (15 minutes).');
}