Canceling JWT tokens in .NET Core

Quite some time ago I published an article (along with the source code) about refreshing the JWTtokens. In the following post, I’m going to focus on canceling the token, thus it can’t be used by anyone else. This tutorial includes the video, so it might be easier to understand the implementation flow.

Given that we do not make use of OAuth (IdentityServer etc.) what can we do in terms of canceling the active tokens? We have a few options:

Remove token on the client side (e.g. local storage) – will do the trick, but doesn’t really cancel the token.

Keep the token lifetime relatively short (5 minutes or so) – most likely we should do it anyway.

Create a blacklist of tokens that were deactivated – this is what we are going to focus on.

The important note is that in order to make it reliable we will use the Redis to store the deactivated tokens on an extremely fast caching server. Whether you host just a single instance of your application or multiple ones, it’s the best idea to use Redis – otherwise, when server goes down, you will lose all of the deactivated tokens blacklist being kept in a default server cache (not to mention the different data if each server would keep its own cache).

Alright, no more theory, proceed with coding, where we will start with the interface:

C#

1

2

3

4

5

6

7

publicinterfaceITokenManager

{

Task<bool>IsCurrentActiveToken();

Task DeactivateCurrentAsync();

Task<bool>IsActiveAsync(stringtoken);

Task DeactivateAsync(stringtoken);

}

And process with its implementation, where the basic idea is to keep track of deactivated tokens only and remove them from a cache when not needed anymore (meaning when the expiry time passed) – they will be no longer valid anyway.

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

publicclassTokenManager:ITokenManager

{

privatereadonlyIDistributedCache _cache;

privatereadonlyIHttpContextAccessor _httpContextAccessor;

privatereadonlyIOptions<JwtOptions>_jwtOptions;

publicTokenManager(IDistributedCache cache,

IHttpContextAccessor httpContextAccessor,

IOptions<JwtOptions>jwtOptions

)

{

_cache=cache;

_httpContextAccessor=httpContextAccessor;

_jwtOptions=jwtOptions;

}

publicasyncTask<bool>IsCurrentActiveToken()

=>awaitIsActiveAsync(GetCurrentAsync());

publicasyncTask DeactivateCurrentAsync()

=>awaitDeactivateAsync(GetCurrentAsync());

publicasyncTask<bool>IsActiveAsync(stringtoken)

=>await_cache.GetStringAsync(GetKey(token))==null;

publicasyncTask DeactivateAsync(stringtoken)

=>await_cache.SetStringAsync(GetKey(token),

" ",newDistributedCacheEntryOptions

{

AbsoluteExpirationRelativeToNow=

TimeSpan.FromMinutes(_jwtOptions.Value.ExpiryMinutes)

});

privatestringGetCurrentAsync()

{

varauthorizationHeader=_httpContextAccessor

.HttpContext.Request.Headers["authorization"];

returnauthorizationHeader==StringValues.Empty

?string.Empty

:authorizationHeader.Single().Split(" ").Last();

}

privatestaticstringGetKey(stringtoken)

=>$"tokens:{token}:deactivated";

}

As you can see, there are 2 helper methods that will use the current HttpContext in order to make things even easier.
Next, let’s create a middleware that will check if the token was deactivated or not. That’s the reason why we should keep them in cache – hitting the database with every request instead would probably kill your app sooner or later (or at least make it really, really slow):

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

publicclassTokenManagerMiddleware:IMiddleware

{

privatereadonlyITokenManager _tokenManager;

publicTokenManagerMiddleware(ITokenManager tokenManager)

{

_tokenManager=tokenManager;

}

publicasyncTask InvokeAsync(HttpContext context,RequestDelegate next)

{

if(await_tokenManager.IsCurrentActiveToken())

{

awaitnext(context);

return;

}

context.Response.StatusCode=(int)HttpStatusCode.Unauthorized;

}

}

Eventually, let’s finish our journey with implementing an endpoint for canceling the tokens:

C#

1

2

3

4

5

6

7

[HttpPost("tokens/cancel")]

publicasyncTask<IActionResult>CancelAccessToken()

{

await_tokenManager.DeactivateCurrentAsync();

returnNoContent();

}

For sure, we could make it more sophisticated, via passing the token via URL, or by canceling all of the existing user tokens at once (which would require an additional implementation to keep track of them), yet this is a basic sample that just works.

Make sure that you will register the required dependencies in your container and configure the middleware:

PREVIOUS POST

NEXT POST

7 Comments →Canceling JWT tokens in .NET Core

Norton Utilities can be broadly defined as a utility software suite, which is designed to provide complete assistance for analyzing, configuring, optimizing and maintaining a system. While downloading, installing or configuring the antivirus on your device, you may face an error. If it happens to you, don’t get panic and call our Norton.com/Setup number 1-888-406-4114. Our technicians will provide you an instant support for Norton Product.