How to secure the Webhook notification

Follow the example to secure Webhook notification.

When sending a request, Litium will use the service account of the receiver to issue a Bearer Token and send it as an authorization header.

To ensure the request which is sent from Litium, it should be authorized by Litium Server.

Follow the example below to know how to secure Webhook notification.

- Create a validator class to validate JWT token and use it as singleton.

public class LitiumTokenValidator
{
    private readonly Lazy<TokenValidationParameters> _tokenValidationParameters;

    public LitiumTokenValidator()
    {
        _tokenValidationParameters = new Lazy<TokenValidationParameters>(() =>
        {
            var client = new HttpClient();
            var doc = client.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest
            {
                Address = LitiumSettings.Host,
                Policy =
                {
                    ValidateIssuerName = false
                }
            }).GetAwaiter().GetResult();

            var keys = new List<SecurityKey>();
            foreach (var webKey in doc.KeySet.Keys)
            {
                var e = Base64Url.Decode(webKey.E);
                var n = Base64Url.Decode(webKey.N);

                var key = new RsaSecurityKey(new RSAParameters { Exponent = e, Modulus = n })
                {
                    KeyId = webKey.Kid
                };

                keys.Add(key);
            }

            return new TokenValidationParameters
            {
                ValidateAudience = false,
                ValidIssuer = doc.Issuer,
                IssuerSigningKeys = keys,

                NameClaimType = JwtClaimTypes.Name,
                RoleClaimType = JwtClaimTypes.Role,

                RequireSignedTokens = true
            };

        });
    }

    public bool Validate(HttpRequestMessage request)
    {
        if (request.Headers.Authorization == null
               || request.Headers.Authorization.Scheme != "Bearer"
               || string.IsNullOrEmpty(request.Headers.Authorization.Parameter))
        {
            return false;
        }

        try
        {
            var handler = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler();
            handler.InboundClaimTypeMap.Clear();

            var claims = handler.ValidateToken(request.Headers.Authorization.Parameter, _tokenValidationParameters.Value, out var _);
            if (claims?.Identity?.Name != LitiumSettings.ClientId)
            {
                return false;
            }
        }
        catch (Exception)
        {
            return false;
        }

        return true;
    }
}

- Now, in order to validate JWT Token, we can create a custom authorization attribute to authorize the action of Asp.NET MVC or validate HttpRequestMessage directly.

public class LitiumTokenAuthorizeAttribute : AuthorizeAttribute
{
    private LitiumTokenValidator LitiumTokenValidator => ServiceLocator.Current.GetInstance<LitiumTokenValidator>();

    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        return base.IsAuthorized(actionContext) && LitiumTokenValidator.Validate(actionContext.Request);
    }
}