I know how to implement a route to register a user and also how to trade user credentials in for an access token. These are both covered in the official tutorial.
How do you invalidate the access token (and refresh token) for a registered user. This is necessary both for logging out and for limiting damage if a user's account is compromised.
I see there is a method
authServer.revokeAllGrantsForResourceOwner(identifier)
but I am still working on how to get the identifier from the user since the client app knows the username but not the user id in the server database. It would be nice to just pass in the current token and have the server cancel all the tokens for that user.
If you want to revoke all tokens given a token, grab the user ID from the authorization token and run a delete query for that user's tokens:
class TokenManagerController extends ResourceController {
@Operation.delete()
Future<Response> deleteTokens() async {
final userId = request.authorization.ownerID;
final query = Query<ManagedAuthToken>(context)
..where((token) => token.resourceOwner).identifiedBy(userId);
final count = await query.delete();
return Response.ok({"userId": userId, "tokensDeleted": count});
}
}
And make sure you link an authorizer:
router.route("/tokens")
.link(() => Authorizer.bearer(authServer))
.link(() => TokenManagerController(context));
FWIW, I recommend having a scope specifically for this action that is only granted for this scenario through an additional login. The UX is that the user has to enter their password again.
If you just want to delete one token, just run a delete query where access_token
= the token in the authorization header.
class LogoutController extends ResourceController {
@Operation.delete()
Future<Response> deleteTokens(@Bind.header('authorization') String authHeader) async {
final parser = AuthorizationBearerParser();
final userToken = parser.parse(authHeader);
final query = Query<ManagedAuthToken>(context)
..where((token) => token.accessToken).equalTo(userToken);
final count = await query.delete();
final userId = request.authorization.ownerID;
return Response.ok({"userId": userId, "tokensDeleted": count});
}
}