File

util/jwt.lua @ 12580:a9dbf657c894 0.12

util.datamapper: Improve handling of schemas with non-obvious "type" The JSON Schema specification says that schemas are objects or booleans, and that the 'type' property is optional and can be an array. This module previously allowed bare type names as schemas and did not really handle booleans. It now handles missing 'type' properties and boolean 'true' as a schema. Objects and arrays are guessed based on the presence of 'properties' or 'items' field.
author Kim Alvefur <zash@zash.se>
date Fri, 08 Jul 2022 17:32:48 +0200
parent 11561:d2f33b8fdc96
child 12696:27a72982e331
line wrap: on
line source

local s_gsub = string.gsub;
local json = require "util.json";
local hashes = require "util.hashes";
local base64_encode = require "util.encodings".base64.encode;
local base64_decode = require "util.encodings".base64.decode;
local secure_equals = require "util.hashes".equals;

local b64url_rep = { ["+"] = "-", ["/"] = "_", ["="] = "", ["-"] = "+", ["_"] = "/" };
local function b64url(data)
	return (s_gsub(base64_encode(data), "[+/=]", b64url_rep));
end
local function unb64url(data)
	return base64_decode(s_gsub(data, "[-_]", b64url_rep).."==");
end

local static_header = b64url('{"alg":"HS256","typ":"JWT"}') .. '.';

local function sign(key, payload)
	local encoded_payload = json.encode(payload);
	local signed = static_header .. b64url(encoded_payload);
	local signature = hashes.hmac_sha256(key, signed);
	return signed .. "." .. b64url(signature);
end

local jwt_pattern = "^(([A-Za-z0-9-_]+)%.([A-Za-z0-9-_]+))%.([A-Za-z0-9-_]+)$"
local function verify(key, blob)
	local signed, bheader, bpayload, signature = string.match(blob, jwt_pattern);
	if not signed then
		return nil, "invalid-encoding";
	end
	local header = json.decode(unb64url(bheader));
	if not header or type(header) ~= "table" then
		return nil, "invalid-header";
	elseif header.alg ~= "HS256" then
		return nil, "unsupported-algorithm";
	end
	if not secure_equals(b64url(hashes.hmac_sha256(key, signed)), signature) then
		return false, "signature-mismatch";
	end
	local payload, err = json.decode(unb64url(bpayload));
	if err ~= nil then
		return nil, "json-decode-error";
	end
	return true, payload;
end

return {
	sign = sign;
	verify = verify;
};