In SynCrypto.pas
and SynEcc.pas
, you will
find:
TJWTAbstract
as abstract parent class for implementing JSON Web Tokens;TJWTNone
implementing the"none"
algorithm;TJWTHS256
implementing the"HS256"
algorithm;TJWTES256
implementing the"ES256"
algorithm.
To generate JWT, you may use
var j: TJWTAbstract; jwt: TJWTContent; ... j := TJWTHS256.Create('secret',0,[jrcSubject],[]); try j.Verify('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibm'+ 'FtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeF'+ 'ONFh7HgQ',jwt); // reference from jwt.io check(jwt.result=jwtValid); check(jwt.reg[jrcSubject]='1234567890'); check(jwt.data.U['name']='John Doe'); check(jwt.data.B['admin']); finally j.Free; end;
The 'eyJhbGciOiJIUzI1NiIsIn...'
token contains in fact the
following, once base-64 decoded:
- header: {
"alg":"HS256","typ":"JWT"}
- payload: {
"sub":"1234567890","name":"John Doe","admin":true}
- signature:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), "secret")
It has a built-in support of claims, so you can write:
j := TJWTHS256.Create('sec',10,[jrcIssuer,jrcExpirationTime,jrcIssuedAt,jrcJWTID],[],60); token := one.Compute(['http://example.com/is_root',true],'joe');
Now, token contains e.g. as signed payload:
{"http://example.com/is_root":true,"iss":"joe","iat":1482177879,"exp":1482181479,"jti":"1496DCE0676925DD33BB5A81"}
Then you can decode such a token, and access its payload in a single method:
j.Verify(token,jwt); assert(jwt.result=jwtValid); assert(jwt.reg[jrcIssuer]='joe');
Integration with method-based services is easy, using
Ctxt.AuthenticationCheck
method:
TMyDaemon = class(... protected fJWT: TJWTAbstract; .... procedure TMyDaemon.Files(Ctxt: TSQLRestServerURIContext); begin if Ctxt.AuthenticationCheck(fJWT)=jwtValid then Ctxt.ReturnFileFromFolder('c:\datafolder'); end;
The above method will define a method-based service returning the content of
a local folder, only if a valid JWT
is supplied within the HTTP
headers of the incoming request.
Feel free to discuss about this new feature in our forum, and check the latest version of the documentation!