getAccessToken method
Returns a valid AccessToken for the clientIdentity
which is at least valid for the time specified in tokenValidBuffer
.
The default value for tokenValidBuffer
is 10 seconds.
Throws NetworkResponseException if the OAuthProxy returns a
bad status code. Throws InvalidJsonSchemaException if the response
from the OAuthProxy is invalid. Throws MaxRetryException if there is
no token bundle at the OAuthProxy after maxRetryPickup exceeded.
Could throw FormatException if the token could not be parsed correctly.
If there is no internet connection a SocketException
is thrown.
Implementation
@override
Future<AccessToken> getAccessToken({int tokenValidBuffer = 10}) async {
if (_accessToken != null && _refreshToken != null) {
//check if current _accessToken is valid
if (_accessToken!.isNotExpired(timeBufferInSeconds: tokenValidBuffer)) {
return _accessToken!;
}
//check if _refreshToken is valid and try to get a new access token
if (_refreshToken!.isNotExpired(timeBufferInSeconds: tokenValidBuffer)) {
final http.Response response =
await http.post(refreshTokenEndpoint, headers: <String, String>{
'content-type': 'application/x-www-form-urlencoded'
}, body: <String, String>{
KeycloakKeys.grantType: KeycloakKeys.refreshToken,
KeycloakKeys.clientId: clientIdentity.id,
KeycloakKeys.clientSecret: clientIdentity.secret,
KeycloakKeys.refreshToken: _refreshToken!.originalToken
});
if (response.statusCode == 200) {
try {
_parseAndSetTokenResponse(response.body);
//_accessToken and _refreshToken should be valid if this is reached
return _accessToken!;
// TODO(poq): test _accessToken.isNotExpired
} catch (e) {
//ignore errors in favor of full flow
}
}
//something went wrong while refreshing token -> try full flow
}
}
//full flow
_invalidateLoginState();
String authInit = '$authProxyBase${'/initialize/${clientIdentity.id}/'
'${clientIdentity.secret}'}';
if (scopes.isNotEmpty) authInit += '/${scopes.join(' ')}';
//send start auth request to oAuthProxy
http.Response response = await http.get(Uri.parse(authInit));
if (response.statusCode != 200) throw NetworkResponseException(response);
try {
final Map<String, dynamic> initBody =
jsonDecode(response.body) as Map<String, dynamic>;
//check response
if (initBody['redirect_url'] != null &&
initBody['proxy_user_identifier'] != null &&
initBody['proxy_secret'] != null) {
//build url for interaction with the user and send it to the application
final String authenticatorUrl =
authProxyBase + initBody['redirect_url'].toString();
await openUrlCallback(Uri.parse(authenticatorUrl));
//start polling at pickup endpoint
final String pollingUrl = "$authProxyBase${"/pickup/"
"${initBody["proxy_user_identifier"].toString()}/"
"${initBody["proxy_secret"].toString()}"}";
final http.Client pickUpClient = http.Client();
for (int i = 0; i < maxRetryPickup; i++) {
response = await pickUpClient.get(Uri.parse(pollingUrl));
await Future<dynamic>.delayed(
Duration(milliseconds: retryWaitingTimeMilliSec));
if (response.statusCode != 200)
throw NetworkResponseException(response);
try {
_parseAndSetTokenResponse(response.body);
//_accessToken and _refreshToken should be
// valid if this code is reached
if (onAuthSuccess != null) onAuthSuccess!();
return _accessToken!;
// TODO(poq): test _accessToken.isNotExpired
} catch (e) {
//answer doesn't includes the needed tokens
}
}
} else {
throw InvalidJsonSchemaException(
'S3I-OAuthProxy returned invalid json', response.body);
}
} on TypeError catch (e) {
throw InvalidJsonSchemaException(
'S3I-OAuthProxy returned invalid json (${e.toString()})',
response.body);
} on FormatException catch (e) {
throw InvalidJsonSchemaException(
'S3I-OAuthProxy returned invalid json (${e.toString()})',
response.body);
}
throw MaxRetryException('Can not receive token bundle from OAuthProxy');
}