Difference between revisions of "JSON Web Token in LSL"

From Second Life Wiki
Jump to navigation Jump to search
(create tutorial for how to build JWT in LSL)
(No difference)

Revision as of 11:03, 31 January 2023

A JSON Web Token a.k.a. JWT (commonly pronounced "jot") is a popular standard for sending authenticated (but not secret!) information in an HTTP request. The JWT string is embedded in a custom http header and is typically validated the receiving web server. The example script below shows how to build and use a JWT via LSL:

// jwt.lsl -- build a JWT in LSL (and use it in an HTTP request)

// The unencrypted private_key must be a PEM-formated string.
string private_key = "-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCTXme8TuUfClUA
qavdVnyIhQaYcPmDxZ2QzfK3f3NO3TL0C+MXLVIFRsTjdnOk12ZSQz1DTQji1Mbk
7Tg1vsEVG91TE2CtO1/XtSjotJ27UbjNg+f5S+856ahv6gTVQDEHLLItmb8YdM0X
Jkcv/1QOzQiieimSj9J45vxw+G62q28oz9FV8UGcCpWnkHTeAH+aB1SRx2YbWvRB
z70u+8gYL/LItp6TH6WI1t9uUSH7gxwdJGllyfCzi+i8YXPr3v6D/tkj6nxxYXgE
MpCwEDUbouM4OiZb4a52E3mdDrttGvKI+jS8s8bqv31FR+Sz2/4kCkBmXVhxnVZl
rlKivyRDAgMBAAECggEACeXSTnnMtmFURN91ypTkzP/aPzd/RVQVeW9Lo6VsvNmV
yCxa4T31qfhkgD5+v+MzsnIPqvXWk0g6ijpLMdjmUPZLztOYr6ndjbhTehBUyQr7
wC82z63uRaklhfa6wl6LAcdaZD5U8QiPPxnJYuDhkr4/Ro0Gk8W9xh8FdMpKwqag
5llYQ0p4XuhvMiNcuFLGzWMcwySQ0DoRJrF4hKp65c+Z4BeWYfl4YF80PURCSMle
aOH6xgi4xYuCtgi9GNbWL/w4mvMq9mpVsLw89sjK8K3ye/P+NBUpeK/zWKGeU1Dl
JgOMMC1wF3Qu1eGOyLMoVcvh5qfPY0p8v1MTyBuPeQKBgQDCpQKHi2zoZlqq0yoN
sDF7pkt3Qd35MFZBVU8YnvIHbnLsoIGf4CoBV8Mc+TEUr5ejzenWJ/FoVjUysoWQ
U+mMNex2yLyg7iWSN55J1XDIL4gR71Ur5BxgeeOsZSooDgJw2/Lhrx3JoHlcy6mD
z7ffxrVhkDYYjOss+Lx1T4vKXQKBgQDB0nBpBlIeO6tp4CKdyjXQtCuPtk/n0l2V
eFwqEfeX5T7f1AXbnYvAMfRgPK5lInPhy/V7YDptSRA032o3wYcJzVwdqNXsyntY
BVjpwhzkZM/v3Pr0JLd4Gf+G7W5W3qWOSFBDsgt033oCCM35ALhnlyYqlmNiYE/o
h7pVzUv/HwKBgDvIdMNu9m9W6KgpHXSA1mH1DJ6/c08TIpsEebvFLe9MZC37inSx
ZBVvgDUI8KM632dnWlf1grcaK1K79DwFGel/snY1Z4JCQvXq8UoaLX6+4psnmFBX
ysNzDJOpqs4Mp4FEfRAGOi7wg/YVc6ZRiVdI7/LcWVEnDyCL8U5StUvdAoGAMF52
5Q7JwXe8oFBp8xy6b1n3IQcrS7wI1LtTrMANHN/939fGmnbnoFAXH0klcGG3r5q5
qU9rZUh9feRfWoi2TXDtUw2GTXB+dYnoFXX2xdyOs9pe2jyreJJsXVy1U4J+qFJN
jYdKKqF2jjlqRYCzhE6JHMmpBazpZCszCiSQmZsCgYAcP8BLQe8xNltPsQ+rVQZp
6F+33LUPMh1rImvuXXhyOuYhrqjLNXD9SqWQeW2+XMqqEI9//lA7UJWTlXbv2Lim
nNDyBPwuZKI3ihVHP6fK1frWfWEDJGJxZ4o4stERcxXg08GhvrBAywfimWRMgy3m
PM5RQOPboW3Hmflau1/mXA==
-----END PRIVATE KEY-----";

key request_id;

// Conversion from base64 to base64URL is done in three steps
//  (1) remove all equal-signs
//  (2) replace 'slash' with 'underscore'
//  (3) replace 'plus' with 'minus'
string base64URL(string input)
{
    integer ALL_INSTANCES = 0;
    string result = llReplaceSubString(input, "=", "", ALL_INSTANCES);
    result = llReplaceSubString(result, "/", "_", ALL_INSTANCES);
    return llReplaceSubString(result, "+", "-", ALL_INSTANCES);
}

// JWT consists of three base64URL-encoded strings separated by dots:
//     header.payload.signature
// where 'signature' is the RSA signature of 'header.payload'
string createJwt(string secret, string header, string payload)
{
    string header_and_payload = base64URL(llStringToBase64(header)) + "." + base64URL(llStringToBase64(payload));
    return header_and_payload + "." + base64URL(llSignRSA(secret, header_and_payload, "sha256"));
}

default
{
    state_entry()
    {
        llOwnerSay("Touch to generate JWT");
    }

    touch_start(integer touch_count)
    {
        // Build a hypothetical JWT which contains: owner_id and expiry
        string algorithm = "RSA256";
        integer expiry_duration = 300; // seconds
        integer expiry = llGetUnixTime() + expiry_duration;
        key owner_id = llGetOwner();
        string header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
        string payload = "{\"sub\":\"" + (string)owner_id + "\",\"exp\":" + (string)expiry + "}";
        string jwt = createJwt(private_key, header, payload);
        llOwnerSay("jwt=" + jwt);

        // Send to a hypothetical web service
        string url = "https://your_web_service_here.com/some/path/here";
        list parameters = [HTTP_METHOD, "GET", HTTP_CUSTOM_HEADER, "Authorization", "Bearer " + jwt];
        request_id = llHTTPRequest(url, parameters, "");
    }

    http_response(key id, integer status, list metadata, string body)
    {
        if (id == request_id)
        {
            llOwnerSay("status=" + (string)status + " body='" + body + "'");
        }
    }
}