Sample code for 30+ languages & platforms
Pascal (Lazarus/Delphi)

OAuth2 Token using IdentityServer4 with Client Credentials

See more OAuth2 Examples

Demonstrates how to get an OAuth2 access token using the client credential flow with IdentityServer4.

Chilkat Pascal (Lazarus/Delphi) Downloads

Pascal (Lazarus/Delphi)
program ChilkatDemo;

// Demonstrates using the Chilkat Pascal wrapper via the C bridge DLL.
// Builds as a console application under Lazarus (FPC) or Delphi.

{$IFDEF FPC}
  {$MODE DELPHI}
{$ENDIF}
{$APPTYPE CONSOLE}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  SysUtils,
  CkDllLoader,
  Chilkat.Http,
  Chilkat.HttpRequest,
  Chilkat.JsonArray,
  Chilkat.HttpResponse,
  Chilkat.JsonObject;

// ---------------------------------------------------------------------------

procedure RunDemo;
var
  success: Boolean;
  http: THttp;
  resp: THttpResponse;
  json: TJsonObject;
  tokenEndpoint: string;
  grantTypes: TJsonArray;
  clientCredentialsIdx: Integer;
  req: THttpRequest;
  accessToken: string;

begin
  success := False;

  //  This example assumes the Chilkat API to have been previously unlocked.
  //  See Global Unlock Sample for sample code.

  http := THttp.Create;

  //  The first step is to fetch your IdentityServer4's discovery document
  //  (OpenID Connect defines a discovery mechanism, called OpenID Connect Discovery, where an OpenID server publishes its metadata at a well-known URL, 
  //  typically https://server.com/.well-known/openid-configuration

  resp := THttpResponse.Create;
  success := http.HttpNoBody('GET','https://localhost:5000/.well-known/openid-configuration',resp);
  if (success = False) then
    begin
      WriteLn(http.LastErrorText);
      Exit;
    end;

  if (resp.StatusCode <> 200) then
    begin
      WriteLn('Received response status code ' + resp.StatusCode);
      WriteLn('Response body containing error text or JSON:');
      WriteLn(resp.BodyStr);
      Exit;
    end;

  json := TJsonObject.Create;
  success := json.Load(resp.BodyStr);

  //  We have the discovery document, which contains something like this:

  //  You can use this online tool to generate parsing code from sample JSON: 
  //  Generate Parsing Code from JSON

  //  {
  //    "issuer": "https://localhost:5000",
  //    "jwks_uri": "https://localhost:5000/.well-known/openid-configuration/jwks",
  //    "authorization_endpoint": "https://localhost:5000/connect/authorize",
  //    "token_endpoint": "https://localhost:5000/connect/token",
  //    "userinfo_endpoint": "https://localhost:5000/connect/userinfo",
  //    "end_session_endpoint": "https://localhost:5000/connect/endsession",
  //    "check_session_iframe": "https://localhost:5000/connect/checksession",
  //    "revocation_endpoint": "https://localhost:5000/connect/revocation",
  //    "introspection_endpoint": "https://localhost:5000/connect/introspect",
  //    "frontchannel_logout_supported": true,
  //    "frontchannel_logout_session_supported": true,
  //    "backchannel_logout_supported": true,
  //    "backchannel_logout_session_supported": true,
  //    "scopes_supported": [
  //      "openid",
  //      "profile",
  //      "email",
  //      "MyCompany.profile",
  //      "MyCompany.Identity.WebApi",
  //      "MyCompany.TriHub.WebApi",
  //      "offline_access"
  //    ],
  //    "claims_supported": [
  //      "sub",
  //      "updated_at",
  //      "locale",
  //      "zoneinfo",
  //      "birthdate",
  //      "gender",
  //      "website",
  //      "profile",
  //      "preferred_username",
  //      "nickname",
  //      "middle_name",
  //      "given_name",
  //      "family_name",
  //      "name",
  //      "picture",
  //      "email_verified",
  //      "email",
  //      "userId",
  //      "groups",
  //      "fullname"
  //    ],
  //    "grant_types_supported": [
  //      "authorization_code",
  //      "client_credentials",
  //      "refresh_token",
  //      "implicit",
  //      "password"
  //    ],
  //    "response_types_supported": [
  //      "code",
  //      "token",
  //      "id_token",
  //      "id_token token",
  //      "code id_token",
  //      "code token",
  //      "code id_token token"
  //    ],
  //    "response_modes_supported": [
  //      "form_post",
  //      "query",
  //      "fragment"
  //    ],
  //    "token_endpoint_auth_methods_supported": [
  //      "client_secret_basic",
  //      "client_secret_post"
  //    ],
  //    "subject_types_supported": [
  //      "public"
  //    ],
  //    "id_token_signing_alg_values_supported": [
  //      "RS256"
  //    ],
  //    "code_challenge_methods_supported": [
  //      "plain",
  //      "S256"
  //    ]
  //  }
  //  

  //  The next steps are to (1) get the token_endpoint,
  //  and (2) verify that the client_credentials grant type is supported.

  tokenEndpoint := json.StringOf('token_endpoint');

  grantTypes := json.ArrayOf('grant_types_supported');
  clientCredentialsIdx := grantTypes.FindString('client_credentials',True);
  grantTypes.Free;

  //  If clientCredentialsIdx is less then zero (-1) then the "client_credentials" string was not found.
  if (clientCredentialsIdx < 0) then
    begin
      WriteLn('The client credentials grant type is not supported.');
      Exit;
    end;

  //  Request the access token using our Client ID and Client Secret.
  //  We're going to duplicate this CURL statement:

  //  curl --request POST \
  //    --url '<tokenEndpoint>' \
  //    --header 'content-type: application/x-www-form-urlencoded' \
  //    --data 'grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET'

  req := THttpRequest.Create;
  req.HttpVerb := 'POST';
  req.ContentType := 'application/x-www-form-urlencoded';

  req.AddParam('grant_type','client_credentials');
  req.AddParam('client_id','CLIENT_ID');
  req.AddParam('client_secret','CLIENT_SECRET');  req.HttpVerb := 'POST';

  success := http.HttpReq(tokenEndpoint,req,resp);
  if (success = False) then
    begin
      WriteLn(http.LastErrorText);
      Exit;
    end;

  //  Make sure we got a 200 response status code, otherwise it's an error.
  if (resp.StatusCode <> 200) then
    begin
      WriteLn('POST to token endpoint failed.');
      WriteLn('Received response status code ' + resp.StatusCode);
      WriteLn('Response body containing error text or JSON:');
      WriteLn(resp.BodyStr);
      Exit;
    end;

  success := json.Load(resp.BodyStr);

  //  Our JSON response should contain this:
  //  {
  //    "access_token":"eyJz93a...k4laUWw",
  //    "token_type":"Bearer",
  //    "expires_in":86400
  //  }

  //  Get the access token:
  accessToken := json.StringOf('access_token');

  //  The access token is what gets added to "Authorization: Bearer <access_token>"
  //  for the subsequent REST API calls..


  http.Free;
  resp.Free;
  json.Free;
  req.Free;

end;

// ---------------------------------------------------------------------------

begin

  try
    RunDemo;
  except
    on E: Exception do
      WriteLn('Unhandled exception: ', E.ClassName, ': ', E.Message);
  end;

  WriteLn;
  {$IFDEF MSWINDOWS}
  WriteLn('Press Enter to exit...');
  ReadLn;
  {$ENDIF}
end.