I'm working on a solution to update the JWT expiry after calls to the server. The problem I am having is getting the auth header. So in the EntityInserted event I have Args.Handler.Request.Headers.Get('authorization') but this fails to retrieve anything.
The aim is to update the token to extend the period of validity:
class function TJWTUtils.UpdateJWT(const AJWT: TJWT): string;
var
JWT: TJWT;
I: Integer;
Pair: TJSONPair;
Value: TJElement;
begin
JWT := TJWT.Create;
try
JWT.Claims.JWTId := AJWT.Claims.JWTId;
JWT.Claims.IssuedAt := AJWT.Claims.IssuedAt;
JWT.Claims.Expiration := TTimeZone.local.ToUniversalTime(IncHour(Now, 2));
for I := 0 to AJWT.Claims.JSON.Count - 1 do
begin
Pair := AJWT.Claims.JSON.Pairs[I];
Value := TJElement.FromJSONValue(Pair.JsonValue);
if Value.IsString then
JWT.Claims.SetClaimOfType<string>(Pair.JsonString.Value, Value.AsString)
else if Value.IsInteger then
JWT.Claims.SetClaimOfType<Integer>(Pair.JsonString.Value, Value.AsInteger)
end;
JWT.Claims.Issuer := TokenIssuer;
Result := TJOSE.SHA256CompactToken(JWTSecret, JWT);
finally
JWT.Free;
end;
end;
Imho this is the way to go. You would have to do the same thing as the JWT Middleware anyway to decode the token. So why not just read the User.Claims.
You can write a custom JWT Middleware extending the Sparkle one, "injecting" your code for creating the new token and setting the response readers with it. Or a new middware that runs after JWT.
Have you checked the actua response returned from the server in the "Network" tab of the browser console? Do you have a screenshot of it? Is the header there in response?
In an XDataServer Event, well it's passed from an event:
procedure TServerContainer.XDataServerEntityInserted(Sender: TObject; Args:
TEntityInsertedArgs);
var
lEntityHelper: TEntityHelper;
begin
{$IFNDEF IMPORTING}
lEntityHelper := FindEntityHelper(Args.Entity, Args);
try
lEntityHelper.AfterInsert;
if lEntityHelper.UpdateJWT(eaInsert) then
UpdateJWT(Args);
finally
lEntityHelper.Free;
end;
{$ENDIF}
end;
procedure TServerContainer.UpdateJWT(Args: TXDataModuleArgs);
var
lJWT: String;
begin
{$IFNDEF IMPORTING}
lJWT := TJWTUtils.UpdateJWT(Args.Handler.Request.User);
if lJWT <> '' then
Args.Handler.Response.Headers.AddValue('jwtupd', lJWT);
{$ENDIF}
end;
class function TJWTUtils.UpdateJWT(AUser: IUserIdentity): string;
var
JWT: TJWT;
lClaim: TUserClaim;
lExpiry: TDateTime;
begin
JWT := TJWT.Create;
try
for lClaim in AUser.Claims do
begin
if lClaim.Name = TReservedClaimNames.ISSUED_AT then
JWT.Claims.IssuedAt := lClaim.AsEpoch
else if lClaim.Name = TReservedClaimNames.JWT_ID then
JWT.Claims.JWTId := lClaim.AsString
else if lClaim.Name = TReservedClaimNames.EXPIRATION then
continue
else if lClaim.IsString then
JWT.Claims.SetClaimOfType<string>(lClaim.Name, lClaim.AsString)
else
JWT.Claims.SetClaimOfType<Integer>(lClaim.Name, lClaim.AsInteger);
end;
JWT.Claims.Expiration := TTimeZone.local.ToUniversalTime(IncMinute(Now, ValidPeriod));
Result := TJOSE.SHA256CompactToken(JWTSecret, JWT);
finally
JWT.Free;
end;
end;