The authorization code has already been received
Unhandled Exception: Bad state: The authorization code has already been received
How to avoid this issue
I am facing the same issue. The process looks as follows:
- The user opens the app and is not authenticated.
- The logic to authenticated the user is triggered. This involves the following two calls:
var grant = oauth2.AuthorizationCodeGrant(CLIENT_ID,
Uri.parse(AUTHORIZATION_ENDPOINT), Uri.parse(TOKEN_ENDPOINT));
var authorizationUrl = grant.getAuthorizationUrl(Uri.parse(REDIRECT_URL),
scopes: ["openid", "offline_access"])
- The user is than redirected to the login page of the authentication server (in my case Keycloak)
- After providing the correct credentials the user is logged in and can start using the app.
- The user logs out
I achieve this by deleting the locally stored credentials and calling.close()on theclient. - If the user logs in immediately again the exact same code as for the first login process is executed. The exception is thrown on the following call:
_client = await grant.handleAuthorizationResponse(
Uri.parse(event.toString()).queryParameters);
If the user restarts the app between logging out and logging in again it works as expected. I assume the issue is that the logout is incomplete. Therefore the State of AuthorizationCodeGrant is finished and the exception is thrown.
How do I properly logout the user and reset the State?
The complete login method looks like this:
@override
Future<void> login() async {
dev.log("start login process");
var grant = oauth2.AuthorizationCodeGrant(CLIENT_ID,
Uri.parse(AUTHORIZATION_ENDPOINT), Uri.parse(TOKEN_ENDPOINT));
var authorizationUrl = grant.getAuthorizationUrl(Uri.parse(REDIRECT_URL),
scopes: ["openid", "offline_access"]);
dev.log("redirect user to login");
if (await canLaunch(authorizationUrl.toString())) {
await launch(authorizationUrl.toString());
}
dev.log("listening for authentication callback");
getLinksStream().listen((event) async {
if (event.toString().startsWith(REDIRECT_URL)) {
_client = await grant.handleAuthorizationResponse(
Uri.parse(event.toString()).queryParameters);
dev.log("client created");
await authDataSource.save(_client.credentials);
_authEventsController.sink
.add(UserAuthenticatedEvent(UserModel(name: "test")));
}
});
}
for anyone facing the same, you need to close the client, close the grant and the subscription, i.e.: with your every logout call the disponse() function:
void dispose() {
grant?.close();
client?.close();
sub?.cancel();
}
I am still having this problem even though doing this and I am using the same package. is there any other way?
Any solution on this??