Sign in Join
Wiki copytemporary

fpJWT: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: fpJWT

OldNewLine
1+fpJWT unit is a part of FCL-Web package in Free Pascal. It provides implementation for "JSON Web Tokens".
2+
3+## Example for login
4+
5+Q: Where can I find an example of using JWT for login?
6+
7+A (by forum member **PierceNg**):
8+
9+In HTTP, a JWT is transmitted in request header like this: "Authorization: Bearer \<jwt\>". The server uses that info to make security decisions.
10+
11+How is the JWT issued to the HTTP client in the first place? By means of some authentication mechanism.
12+
13+What authentication mechanism? Depends on client. Different for human driving web browser that is running an SPA and automated client making REST calls, as examples.
14+
15+``` Pascal
16+ jwt:= TJWT.Create(TJWTClaims);
17+ try
18+ jwt.Claims.iss:= issuer;
19+ jwt.Claims.exp:= Now + EncodeTime(0, minutesToExpire, 0, 0)]);
20+ jwt.Claims.sub:= subject;
21+ jwt.JOSE.alg:= 'HS256';
22+ jwt.JOSE.typ:= 'JWT';
23+ finally
24+....
25+```
26+
27+It should be an authentication component that issues the JWT. I assume your CGI program will consume the JWT. How does the client of your CGI handle issuance and use of the JWT?
28+
29+Some useful reading:
30+
31+- <https://blog.paolorossi.net/jwt-authentication-with-delphi-part-1/>
32+- <https://blog.logrocket.com/jwt-authentication-best-practices/>
33+- <https://stackoverflow.com/questions/27067251/where-to-store-jwt-in-browser-how-to-protect-against-csrf>
34+
35+## Custom claims
36+
37+Q: I'm porting an application from Delphi, and with Paolo Rossi JWT implementation is possible to add custom claims. I took a look into the source and couldn't figure out how to do it.
38+
39+A (forum member **PascalDragon**): You need to create a descendant of TClaims with the custom claims as properties (please note that the property names will be used as is for the claims, so mind the casing). See the example in /packages/fcl-web/examples/jwt/signrs256.lpr.
40+
41+``` Pascal
42+ // claims
43+ jwt.Claims.exp:=DateTimeToUnix(Now+10);
44+ jwt.Claims.iss:='FPC JWT';
45+ with jwt.Claims as TMyClaims do
46+ Name := 'Myself';
47+
48+ { ... }
49+
50+ // verify our generated token. This generates a new JWT
51+ VerifyResult:=TMyJWT.ValidateJWT(aInput,Key);
52+ if VerifyResult=Nil then
53+ Raise Exception.Create('No verify resultn, verification failed!');
54+
55+ with VerifyResult.Claims as TMyClaims do
56+ Writeln(Name, ' ', admin);
57+```
58+
59+You could also adjust your TJWT descendant like this so that you can directly use your TClaims descendant:
60+
61+``` Pascal
62+ // A JWT that uses our claims
63+ TMyJWT = Class(TJWT)
64+ private
65+ function GetClaims: TMyClaims;
66+ protected
67+ Function CreateClaims : TClaims; override;
68+ public
69+ property Claims: TMyClaims read GetClaims;
70+ end;
71+
72+function TMyJWT.GetClaims: TMyClaims;
73+begin
74+ Result := TMyClaims(inherited Claims);
75+end;
76+
77+function TMyJWT.CreateClaims: TClaims;
78+begin
79+ Result:=TMyClaims.Create;
80+end;
81+
82+{ ... }
83+
84+var
85+ aInput, aPrivateKeyPEM, aPublicKeyPEM: String;
86+ Key: TJWTKey;
87+ JWT : TJWT;
88+ VerifyResult: TMyJWT; { <=== !!!! }
89+ Signer: TJWTSigner;
90+ NewDER: TBytes;
91+ RSAPublic: TX509RSAPublicKey;
92+ RSAPrivate: TX509RSAPrivateKey;
93+
94+{ ... }
95+
96+ // verify our generated token. This generates a new JWT
97+ VerifyResult:=TMyJWT.ValidateJWT(aInput,Key) as TMyJWT;
98+ if VerifyResult=Nil then
99+ Raise Exception.Create('No verify resultn, verification failed!');
100+ Writeln(VerifyResult.Claims.Name, ' ', VerifyResult.Claims.admin);
101+```
102+
103+## Signature generation
104+
105+(from forum member **paweld**). In FPC 3.2.2 there is no signature generation yet - so you must either use the component: <https://github.com/andre-djsystem/LazJWT>, or use fpJWT to generate JOSE and Claims and using <https://github.com/Xor-el/HashLib4Pascal> generate a signature, e.g.
106+
107+``` Pascal
108+uses
109+ fpjwt, HlpIHashInfo, HlpConverters, HlpHashFactory, DateUtils, Base64;
110+
111+procedure TForm1.FormCreate(Sender: TObject);
112+begin
113+ ShowMessage(GenJwt('xxx', 'yyy', 'password', 60));
114+end;
115+
116+function TForm1.GenJwt(issuer, subject, secret_key: String; minutesToExpire: Integer): String;
117+var
118+ jwt: TJWT;
119+ LHMAC: IHMAC;
120+ barr: TBytes;
121+ s: String;
122+ i: Integer;
123+begin
124+ jwt := TJWT.Create;
125+ jwt.Claims.iss:= issuer;
126+ jwt.Claims.exp:= DateTimeToUnix(IncMinute(Now, minutesToExpire));
127+ jwt.Claims.sub:= subject;
128+ jwt.JOSE.alg:= 'HS256';
129+ jwt.JOSE.typ:= 'JWT';
130+ Result := jwt.JOSE.AsEncodedString + '.' + jwt.Claims.AsEncodedString;
131+ LHMAC := THashFactory.THMAC.CreateHMAC(THashFactory.TCrypto.CreateSHA2_256);
132+ LHMAC.Key := TConverters.ConvertStringToBytes(secret_key, TEncoding.UTF8);
133+ barr := LHMAC.ComputeString(Result, TEncoding.UTF8).GetBytes();
134+ s := '';
135+ for i := Low(barr) to High(barr) do
136+ s := s + chr(barr[i]);
137+ jwt.Signature := jwt.Base64ToBase64URL(EncodeStringBase64(s));
138+ Result := Result + '.' + jwt.Signature;
139+ jwt.Free;
140+end;
141+```
142+
143+(from forum member **WayneSherman**). JWT signing was added to FPC trunk in 2022:
144+
145+- <https://gitlab.com/freepascal.org/fpc/source/-/tree/main/packages/fcl-web/examples/jwt>
146+- <https://gitlab.com/freepascal.org/fpc/source/-/tree/main/packages/fcl-web/src/jwt>
147+
148+---
149+*From the Free Pascal wiki, page "fpJWT", as it stood on 2023-03-19 after a change by Alextp, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history