Jump to content
Lars Fosdal

OAuth2 bearer token example?

Recommended Posts

I am stumped.

 

I can't convince the Delphi TRESTClient to connect to a system using OAuth2 authentication.  

Either it is a about a parameterization mistake, or it is a functional failure.

 

I can't get it to work with the REST debugger either.

 

Any examples (Other than the RESTdemo) would be appreciated!

 

I have C# code that uses the same creds, and it has no issues.

I get access to the system using the Authentication URL with the clientid + clientsecret

I request a token through a different URL

I call the API URL, using the token

 

 

Share this post


Link to post

The authentication can be implemented in severeal ways. I would sniff the traffic and see the difference oooooor read the manual.

 

Usually there are some "postman" (Application) examples.

Edited by Attila Kovacs

Share this post


Link to post

I have instrumented the C# app with logging, so I see exactly what happens.

The challenge is convincing the Delphi REST components to do the same thing.

Share this post


Link to post

It is possible that you have to implement it yourself in the way it is needed as it is noted in the docs:

Quote

TOAuth2Authenticator implements a basic OAuth2 authentication. TOAuth2Authenticator offers minimal support and provides the infrastructure to follow the workflow of the service provider.

Inherit from this class to create an authenticator class specific to a service provider.

That said, giving a concrete example is difficult without knowing more details.

  • Thanks 1

Share this post


Link to post

OAuth2 is the authentication protocol. How the credentials are exchanged is up to the service provider. There are some common ways like pass it in the URL (RESTDebugger) or pass it in the headers, pass it in a JSON Object etc... The service provider will give you the documentation and examples.

Share this post


Link to post

I think I was fooled by my own expectations with regards to the simplicity of OAuth2 and functional level of the TOAuth2Authenticator.

 

The C# code example can be found here, but it uses another assembly from Thinktecture to do the http parts.

https://github.com/LarsFosdal/csharp-ion-api-sdk/blob/master/DotNetBackendOAuth2/Program.cs

 

I'll ponder a little, google some more, and see if I can't crack this nut.

 

Share this post


Link to post

I ended up writing a small class around THTTPClient from System.Net.HttpClient.

No need for the humongous REST.* classes.

  • Like 1

Share this post


Link to post
On 1/12/2023 at 9:07 AM, Attila Kovacs said:

did you ask chatGPT for an example? :classic_cheerleader:

I just did for fun.  Here's the result:

 

 

 

Can you create an example OAuth2 bearer token example in Delphi using the THTTPClient ?

 

Sure, here is an example of how to use the THTTPClient component in Delphi to authenticate with an OAuth2 bearer token:

uses
  System.Net.HttpClient, System.Net.URLClient, System.NetConsts;

function SendRequestWithBearerToken(const AURL: string; const AToken: string): string;
var
  Client: THTTPClient;
  Request: THTTPRequest;
  Response: IHTTPResponse;
begin
  Client := THTTPClient.Create;
  Request := THTTPRequest.Create(TNetEncoding.Base64);
  try
    Request.Method := TRESTRequestMethod.rmGET;
    Request.URL := AURL;
    Request.Headers.AddValue('Authorization', 'Bearer ' + AToken);

    Response := Client.Execute(Request);

    if Response.StatusCode = 200 then
      Result := Response.ContentAsString
    else
      raise Exception.CreateFmt('Request failed with HTTP error %d: %s', [Response.StatusCode, Response.StatusText]);
  finally
    Request.Free;
    Client.Free;
  end;
end;

In this example, the SendRequestWithBearerToken function takes two parameters:

AURL: The URL of the API endpoint that you want to call.
AToken: The OAuth2 bearer token that you want to use for authentication.
The function creates a THTTPClient object to send the HTTP request, and a THTTPRequest object to set up the request headers. It sets the HTTP method to GET and sets the URL and Authorization header with the bearer token.

Finally, it sends the request using the Execute method of the THTTPClient object and returns the response as a string.

You can call this function like this:

 

var
  ResponseContent: string;
begin
  try
    ResponseContent := SendRequestWithBearerToken('https://api.example.com/items', 'my_bearer_token');
    // Process the response content here
  except
    on E: Exception do
      ShowMessage('Error: ' + E.Message);
  end;
end;

Note that in this example, you would need to replace the https://api.example.com/items with the actual API endpoint you want to call, and my_bearer_token with the actual OAuth2 bearer token that you want to use for authentication.

  • Like 1

Share this post


Link to post

This might help. It took me a while to track down.

 

Using the REST Debugger, just put "Bearer " in front of the token and select OAuth2. When you get it working, click the option to copy the components and paste the result onto your form.

 

One of the components it creates is this component, which is in the REST.Authenticator.OAuth unit:

 

image.png.6cae340e7273b781ebf023b3c6c86521.png

 

You set the TokenType to ttBEARER, set the Access Token, and tell it the name of the parameter, and I think that's it.

 

 

 

Share this post


Link to post

What lacks in this example is that the bearer token can be a temporary token, and you first have to authenticate to retrieve the bearer token and the renewal token, and use the renewal token periodically to update your tokens.

Share this post


Link to post
15 hours ago, Lars Fosdal said:

What lacks in this example is that the bearer token can be a temporary token, and you first have to authenticate to retrieve the bearer token and the renewal token, and use the renewal token periodically to update your tokens.

Maybe you need to find less paranoid services to work with. 🙂 🙂 🙂 

Edited by David Schwartz

Share this post


Link to post

Have you tried the TOAuth2Authenticator component linked to a TRESTClient? It has a context menu that lets you specify play with some parameters.

Share this post


Link to post

Jumping in here... I am new to much of this. I have a client certificate and key file (.pem and .key). I have successfully used Postman (new to that too) to send an HTTP Post request to get a bearer token. To do this I added my client cert in Postman settings:

 

image.png.d5341d1ea91ed46dc309952250dfc899.png

 

And the HTTP request has several parameters in the body and header, which I added on the Postman request pages. It works! The response looks like this:

 

{
    "access_token""20c686eb-1313-4e53-9d73-df1626dd3996",
    "token_type""Bearer",
    "expires_in"3600,
    "scope""api"
}
 
Using the bearer token I'm then able to make api calls for 60 minutes.
 
My question is, can someone tell me how to add the client certificate to the Delphi RestClient or RestRequest? I'm looking at the OAuth2Authenticator component but it's not obvious to me what I need to do.
 
I think I have all the parameters set up in the RestRequest successfully, but without the client cert I'm getting an error, "unspecified certificate from client"

Share this post


Link to post
Quote

how to add the client certificate to the Delphi RestClient or RestRequest?

Client certificates are unrelated to REST, OAuth2 or tokens.  They are an alternate means of server authentication by HTTPS clients to HTTPS servers, not that common except for corporate VPNs and high security financial applications.  It is quite hard to buy a commercial client certificate, for email for instance, they are usually issued by corporates for employees and customers.

 

I don't use the TRestClient component, but I'm not aware it supports client certificates.  You need a proper component library like ICS that has full support for REST, Auth2, tokens and client certificates.

 

Angus

 

Share this post


Link to post

Yes, but the ICS download page is http://wiki.overbyte.eu/wiki/index.php/ICS

 

Once you have it installed run the SSLDemos OverbyteIcsHttpRestTst sample, it does everything you need.  However that sample expects your client certificate to be provided as a bundle file for ease of configuration, ie the certificate, key and intermediate in a single PEM or PFX file.  The PemTool sample does all that, although a text editor also works for PEM.

 

There is an ICS support topic here.

 

Angus

 

Share this post


Link to post

Thanks again. Rookie question - my URL starts https://, not http://. Is that enough to require OpenSSL, or how do I determine if I need to use OpenSSL?

 

From the wiki - "You will also need OpenSSL libraries if using SSL-enabled components"

 

I am reading the notes and if I answer my own question I will post again.

Share this post


Link to post

Options to ICS? It's free which is great but appears development has stopped? The app I'm creating might be needed for several years. Is there an option that is well regarded and actively updated?

Share this post


Link to post
Quote

Options to ICS? It's free which is great but appears development has stopped?

Why would you think that?  The last release was in November 2022 which you can install from GetIt, and the latest SVN update was last week.  The latest OpenSSL DLLs are installed with the samples, updated this month. 

 

Angus

 

Share this post


Link to post

The first page I found stated the last supported version was D10.3, screen capture below. Thanks for correcting me. I have an issue with install on Berlin.

 

I load project D101InstallVclFmx and all projects compile, but when I try to install the design packages I get this error:

 

image.png.047240a6db5032e93579cad13e8dddbc.png

 

One note - I'm using Berlin - Please ignore the folder name "Delphi Tokyo"... it is misnamed.

 

The file is in that folder, so I'm stumped:

image.thumb.png.f0eb40bb4a5ccc65a96231a6d2ac1f2e.png

 

What should I look at to correct that?

 

This is why I thought development had stopped:

 

image.thumb.png.238034ae8e192ef2fc9f5c5d5a0b53c7.png

Share this post


Link to post

It is probably another module (BPL or DLL) that is internally used by the mentioned package, but is either missing or fails to load.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×