Trying to get JWT working - what have I missed ?

Following the documentation I have done this.

Login service

function TAux.Login_Token   (const AUser : string;    const APwd  : string) : string;
var
  JWT     : TJWT;
  Scopes  : string;
  LResult : TLogin_Block;
begin
  LResult := DBase.User_Valid (AUser, APwd);
  if not LResult.Is_Valid
  then raise Exception{EXDataHttpUnauthorized}.Create (err_Invalid_Login);

  JWT := TJWT.Create;
  try
    JWT.Claims.SetClaimOfType<string> ('user', AUser);
    if LResult.Is_Admin
    then JWT.Claims.SetClaimOfType<Boolean>('admin', True);
    if LResult.Is_Super
    then JWT.Claims.SetClaimOfType<Boolean>('super', True);

    Scopes := 'reader writer';
    JWT.Claims.SetClaimOfType<string>('scope', Scopes);
    JWT.Claims.Issuer := 'XData Server';
    Result := TJOSE.SHA256CompactToken (Srv_Secret, JWT);
  finally
    JWT.Free;
  end;
end;

In Data Module on Server

  srvJWT.Secret := Srv_Secret;

On the Client I get the token and save it

procedure TAux.Login_Token (AUser,  APwd  : string;
                 ACBFailed  : TCB_String;
                ACBSuccess : TCB_Boolean);

  procedure OnResult (Response : TXDataClientResponse);
  var
    LRes : string;
  begin
    if Response.StatusCode = Http_Ok
    then begin
         LRes := string(TJSObject (Response.Result)['value']);
         {$ifdef Use_JWT}
         Server.Token := LRes;
         {$endif}
         ACBSuccess (True);
    end
    else begin
         LRes := '';
         ACBFailed ('');
    end;
  end;

  procedure OnError (Error: TXDataClientError);
  begin
    Log (Error);
    ACBFailed ('');
  end;

begin
  Check_Connection;
  xdcAux.RawInvoke (Svc+'Login_Token', [AUser, APwd],
                    @OnResult, @OnError);
end;

On the client I use the saved token from above in the ConnectionRequest

procedure TServer.ApiConnectionRequest (Args : TXDataWebConnectionRequest);
begin
  if Token <> ''
  then Args.Request.Headers.SetValue
       ('Authorization', 'Bearer ' + Token);
end;

I have not set any attributes on the Entities. Fuel, below, is one of the entities.

I am getting

GET http://localhost:2002/chopper/Fuel?$top=0&$inlinecount=allpages 401 (Unauthorized)

{FMessage: 'XData server request error.
Uri: http://localhost:…nlinecount=allpages\nStatus code: 401
Unauthorized', FHelpContext: 0, FJSError: Error: XData server request error.
Uri: http://localhost:2002/chopper/Fuel?$top=0&$inlinecount=allp…, FStack: 'Error: XData server request error.
Uri: http://loc…ttp://localhost:8000/ops/ops_1_0_273.js:56475:34)', FErrorResult: {…}}

Questions

  1. What have I missed? If I don't set the header on ConnectionRequest ,then it works fine after login.
  2. Is it somehow, because I am using the same service for Login endpoint as the rest of the Entities?
  3. Can I set a header of my own name and implement my own security? How do I retrieve the header on the server.

I wrote up an example of using JWTs with XData with a login function here, where the client section is implemented in the follow-on post. Maybe you can get something from here to help you with your implementation?

Thanks,

I will have a look at the entire project from Github. It does require more time. I need to finish the login so I can bill the client for this stage of the project (with or without JWT) :slight_smile:

But I did notice one difference

    JWTSTring := 'Bearer '+TJOSE.SHA256CompactToken(ServerContainer.XDataServerJWT.Secret, JWT);  

You have the word Bearer here, which was not on the docs I was looking at.

However, I do have the word Bearer at the client end

 if Token <> ''
  then Args.Request.Headers.SetValue
       ('Authorization', 'Bearer ' + Token);

Qs: what is the purpose or significance of the word Bearer?

It's just a standard, it's a way to tell what is the type of the token you are passing.

What happens if you temporarily remove the JWT middleware from your server,t thus leaving it unprotected. Do you still get 401 or 200?

It works without it.

It works, even if remove this at the client.

procedure TServer.ApiConnectionRequest (Args : TXDataWebConnectionRequest);
begin
  if Token <> ''
  then Args.Request.Headers.SetValue
       ('Authorization', 'Bearer ' + Token);
end;

Then your token is simply invalid, for some reason.