Skip to content

Instantly share code, notes, and snippets.

@wqweto
Created March 30, 2023 11:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wqweto/c069aeaad424091f6b8813bd9d8776de to your computer and use it in GitHub Desktop.
Save wqweto/c069aeaad424091f6b8813bd9d8776de to your computer and use it in GitHub Desktop.
Encode JSON Web Token in MSSQL
IF OBJECT_ID('fn_sys_GetEncodedJwt') IS NOT NULL DROP FUNCTION fn_sys_GetEncodedJwt
GO
/*
DECLARE @Header NVARCHAR(MAX) = N'{"alg":"HS512","typ":"JWT"}', @Payload NVARCHAR(MAX) = N'{"sub":"1234567890","name":"JohnDoe","iat":1516239022}'
SELECT dbo.fn_sys_GetEncodedJwt('HS512', @Header, @Payload, CONVERT(VARBINARY(MAX), 'Password'))
*/
CREATE FUNCTION fn_sys_GetEncodedJwt (
@Algo VARCHAR(50)
, @Header NVARCHAR(MAX)
, @Payload NVARCHAR(MAX)
, @Secret VARBINARY(MAX)
) RETURNS VARCHAR(MAX)
WITH SCHEMABINDING AS
BEGIN
DECLARE @BlockSize INT
, @Idx INT
, @Data VARBINARY(MAX)
, @InnerPad VARBINARY(MAX)
, @OuterPad VARBINARY(MAX)
--- data = base64urlEncode( header ) + "." + base64urlEncode( payload )
SET @Data = CONVERT(VARBINARY(MAX), CONVERT(VARCHAR(MAX), @Header COLLATE Latin1_General_100_CI_AI_SC_UTF8))
SET @Header = REPLACE(REPLACE(REPLACE(CONVERT(XML, '').value('xs:base64Binary(sql:variable("@Data"))', 'VARCHAR(MAX)'), '+', '-'), '/', '_'), '=', '')
SET @Data = CONVERT(VARBINARY(MAX), CONVERT(VARCHAR(MAX), @Payload COLLATE Latin1_General_100_CI_AI_SC_UTF8))
SET @Payload = REPLACE(REPLACE(REPLACE(CONVERT(XML, '').value('xs:base64Binary(sql:variable("@Data"))', 'VARCHAR(MAX)'), '+', '-'), '/', '_'), '=', '')
SET @Data = CONVERT(VARBINARY(MAX), CONVERT(VARCHAR(MAX), COALESCE(@Header + '.', '') + @Payload))
--- hashedData = hash( data, secret )
SET @Algo = CASE @Algo WHEN 'HS512' THEN 'SHA2_512' WHEN 'HS256' THEN 'SHA2_256' ELSE @Algo END
SET @BlockSize = CASE @Algo WHEN 'SHA2_512' THEN 128 WHEN 'MD2' THEN 16 ELSE 64 END
SET @Secret = CASE WHEN LEN(@Secret) > @BlockSize THEN HASHBYTES(@Algo, @Secret) ELSE @Secret END
SELECT @InnerPad = 0x, @OuterPad = 0x, @Idx = 1
WHILE @Idx <= @BlockSize
BEGIN
SELECT @InnerPad = @InnerPad + CONVERT(VARBINARY(1), SUBSTRING(@Secret, @Idx, 1) ^ 54)
, @OuterPad = @OuterPad + CONVERT(VARBINARY(1), SUBSTRING(@Secret, @Idx, 1) ^ 92)
, @Idx = @Idx + 1
END
SET @Data = HASHBYTES(@Algo, @OuterPad + HASHBYTES(@Algo, @InnerPad + @Data))
--- signature = base64urlEncode( hashedData )
RETURN COALESCE(@Header + '.', '') + @Payload + '.' + REPLACE(REPLACE(REPLACE(CONVERT(XML, '').value('xs:base64Binary(sql:variable("@Data"))', 'VARCHAR(MAX)'), '+', '-'), '/', '_'), '=', '')
END
GO
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment