Chilkat Examples

ChilkatHOME.NET Core C#Android™AutoItCC#C++Chilkat2-PythonCkPythonClassic ASPDataFlexDelphi ActiveXDelphi DLLGoJavaLianjaMono C#Node.jsObjective-CPHP ActiveXPHP ExtensionPerlPowerBuilderPowerShellPureBasicRubySQL ServerSwift 2Swift 3,4,5...TclUnicode CUnicode C++VB.NETVBScriptVisual Basic 6.0Visual FoxProXojo Plugin

DataFlex Examples

Web API Categories

ASN.1
AWS KMS
AWS Misc
Amazon EC2
Amazon Glacier
Amazon S3
Amazon S3 (new)
Amazon SES
Amazon SNS
Amazon SQS
Async
Azure Cloud Storage
Azure Key Vault
Azure Service Bus
Azure Table Service
Base64
Bounced Email
Box
CAdES
CSR
CSV
Certificates
Code Signing
Compression
DKIM / DomainKey
DNS
DSA
Diffie-Hellman
Digital Signatures
Dropbox
Dynamics CRM
EBICS
ECC
Ed25519
Email Object
Encryption
FTP
FileAccess
Firebase
GMail REST API
GMail SMTP/IMAP/POP
Geolocation
Google APIs
Google Calendar
Google Cloud SQL
Google Cloud Storage
Google Drive
Google Photos
Google Sheets
Google Tasks
Gzip
HTML-to-XML/Text
HTTP

HTTP Misc
IMAP
JSON
JSON Web Encryption (JWE)
JSON Web Signatures (JWS)
JSON Web Token (JWT)
Java KeyStore (JKS)
MHT / HTML Email
MIME
MS Storage Providers
Microsoft Graph
Misc
NTLM
OAuth1
OAuth2
OIDC
Office365
OneDrive
OpenSSL
Outlook
Outlook Calendar
Outlook Contact
PDF Signatures
PEM
PFX/P12
PKCS11
POP3
PRNG
REST
REST Misc
RSA
SCP
SCard
SFTP
SMTP
SSH
SSH Key
SSH Tunnel
ScMinidriver
SharePoint
SharePoint Online
Signing in the Cloud
Socket/SSL/TLS
Spider
Stream
Tar Archive
ULID/UUID
Upload
WebSocket
XAdES
XML
XML Digital Signatures
XMP
Zip
curl
uncategorized

 

 

 

(DataFlex) Azure OpenID Connect Step 2 -- Get id_token and Validate

See more OIDC Examples

After getting the endpoints by querying the Azure's OIDC well-known discovery document (OpenID Configuration document), we use the authorization_endpoint to get the id_token, and then validate it..

For more information, see https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc

Chilkat ActiveX Downloads

ActiveX for 32-bit and 64-bit Windows

Use ChilkatAx-9.5.0-win32.pkg

Procedure Test
    Boolean iSuccess
    String sAuthorization_endpoint
    String sJwks_uri
    Handle hoReq
    Handle hoPrng
    String sEncodedParams
    Handle hoSbUrl
    String sUrl
    Handle hoListenSock
    Integer iBackLog
    Integer iMaxWaitMs
    Variant vTask
    Handle hoTask
    Handle hoSock
    String sStartLine
    String sRequestHeader
    Variant vSbRequestBody
    Handle hoSbRequestBody
    Variant vSbResponseHtml
    Handle hoSbResponseHtml
    Handle hoSbResponse
    Handle hoHashTab
    String sIdToken
    Handle hoJwt
    Integer iLeeway
    Boolean iBTimeValid
    String sPayload
    Handle hoJson
    String sJoseHeader
    Handle hoJsonJoseHeader
    Variant vSbJwks
    Handle hoSbJwks
    Handle hoHttp
    Handle hoJwkset
    String sKid
    Variant vJwk
    Handle hoJwk
    Boolean iVerified
    Variant vPubkey
    Handle hoPubkey
    String sTemp1
    Integer iTemp1
    Boolean bTemp1

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

    // In our previous example (Azure Fetch OpenID Connect metadata document) we fetched
    // the OpenID configuration document which is JSON which contains an entry for authorization_endpoint.

    Move "https://login.microsoftonline.com/6d8ddd66-68d1-43b0-af5c-e31b4b7dd5cd/oauth2/v2.0/authorize" To sAuthorization_endpoint

    // The OpenID Connect metadata document also contained a jwks_uri entry.  This is the JSON Web Key Set (JWKS),
    // which is a set of keys containing the public keys used to verify any JSON Web Token (JWT) (in this case the id_token)
    // issued by the authorization server and signed using the RS256 signing algorithm. 
    Move "https://login.microsoftonline.com/6d8ddd66-68d1-44b0-af5c-e31b4b7ee5cd/discovery/v2.0/keys" To sJwks_uri

    // We're going to send the following GET request, but it will be sent through an interactive web browser (not by Chilkat).
    // The following code will form the URL that is to be programmatically loaded and sent in a browser.

    // GET https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
    // client_id=6731de76-14a6-49ae-97bc-6eba6914391e
    // &response_type=id_token
    // &redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
    // &response_mode=form_post
    // &scope=openid
    // &state=12345
    // &nonce=678910

    // Use this object to set params and then get the URL-encoded query params string 
    Get Create (RefClass(cComChilkatHttpRequest)) To hoReq
    If (Not(IsComObjectCreated(hoReq))) Begin
        Send CreateComObject of hoReq
    End
    Send ComAddParam To hoReq "client_id" "f125d695-c50e-456e-a579-a486f06d1213"
    Send ComAddParam To hoReq "response_type" "id_token"
    Send ComAddParam To hoReq "redirect_uri" "http://localhost:3017/"
    Send ComAddParam To hoReq "response_mode" "form_post"
    Send ComAddParam To hoReq "scope" "openid"
    Get Create (RefClass(cComChilkatPrng)) To hoPrng
    If (Not(IsComObjectCreated(hoPrng))) Begin
        Send CreateComObject of hoPrng
    End
    Get ComGenRandom Of hoPrng 3 "decimal" To sTemp1
    Send ComAddParam To hoReq "state" sTemp1
    Get ComGenRandom Of hoPrng 4 "decimal" To sTemp1
    Send ComAddParam To hoReq "nonce" sTemp1

    Get ComGetUrlEncodedParams Of hoReq To sEncodedParams
    Showln sEncodedParams

    // Sample URL encoded params:
    // client_id=6731de76-14a6-49ae-97bc-6eba6914391e&redirect_uri=http%3A%2F%2Flocalhost%3A3017%2F&response_mode=form_post&scope=openid&state=3572902&nonce=57352474

    // This is the URL to be programmatically loaded and sent in an interactive web browser..
    Get Create (RefClass(cComChilkatStringBuilder)) To hoSbUrl
    If (Not(IsComObjectCreated(hoSbUrl))) Begin
        Send CreateComObject of hoSbUrl
    End
    Get ComAppend Of hoSbUrl sAuthorization_endpoint To iSuccess
    Get ComAppend Of hoSbUrl "?" To iSuccess
    Get ComAppend Of hoSbUrl sEncodedParams To iSuccess
    Get ComGetAsString Of hoSbUrl To sUrl

    // Before we launch the browser with the contents of sbUrl, create a socket to listen for the eventual callback..

    Get Create (RefClass(cComChilkatSocket)) To hoListenSock
    If (Not(IsComObjectCreated(hoListenSock))) Begin
        Send CreateComObject of hoListenSock
    End

    // Listen at the port indicated by the redirect_uri above.
    Move 5 To iBackLog
    Get ComBindAndListen Of hoListenSock 3017 iBackLog To iSuccess
    If (iSuccess <> True) Begin
        Get ComLastErrorText Of hoListenSock To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    // Wait for the browser's connection in a background thread.
    // (We'll send load the URL into the browser following this..)
    // Wait a max of 60 seconds before giving up.
    Move 60000 To iMaxWaitMs
    Get ComAcceptNextConnectionAsync Of hoListenSock iMaxWaitMs To vTask
    If (IsComObject(vTask)) Begin
        Get Create (RefClass(cComChilkatTask)) To hoTask
        Set pvComObject Of hoTask To vTask
    End
    Get ComRun Of hoTask To iSuccess

    // -------------------------------------------------------------------
    // At this point, your application should load the URL in a browser.
    // You'll need to add code here to do it..

    // For example, 
    // in C#: System.Diagnostics.Process.Start(url);
    // in Java: Desktop.getDesktop().browse(new URI(url));
    // in VBScript: Set wsh=WScript.CreateObject("WScript.Shell")
    //              wsh.Run url
    // in Xojo: ShowURL(url)  (see http://docs.xojo.com/index.php/ShowURL)
    // in Dataflex: Runprogram Background "c:\Program Files\Internet Explorer\iexplore.exe" sUrl        
    // The account owner would interactively accept or deny the authorization request.

    // Add the code to load the url in a web browser here...
    // Add the code to load the url in a web browser here...
    // Add the code to load the url in a web browser here...
    // System.Diagnostics.Process.Start(url);

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

    // Wait for the listenSock's task to complete.
    Get ComWait Of hoTask iMaxWaitMs To iSuccess
    Get ComStatusInt Of hoTask To iTemp1
    Get ComTaskSuccess Of hoTask To bTemp1
    If (Not iSuccess Or (iTemp1 <> 7) Or (bTemp1 <> True)) Begin
        If (Not iSuccess) Begin
            // The task.LastErrorText applies to the Wait method call.
            Get ComLastErrorText Of hoTask To sTemp1
            Showln sTemp1
        End
        Else Begin
            // The ResultErrorText applies to the underlying task method call (i.e. the AcceptNextConnection)
            Get ComStatus Of hoTask To sTemp1
            Showln sTemp1
            Get ComResultErrorText Of hoTask To sTemp1
            Showln sTemp1
        End

        Send Destroy of hoTask
        Procedure_Return
    End

    // If we get to this point, a connection on listenSock was accepted, and the redirected POST
    // is waiting to be read on the connected socket.
    // The POST we are going to read contains the following:

    // POST /myapp/ HTTP/1.1
    // Host: localhost
    // Content-Type: application/x-www-form-urlencoded
    // 
    // id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNB...&state=12345

    // But first.. we no longer need the listen socket...
    // Stop listening on port 3017.
    Get ComClose Of hoListenSock 10 To iSuccess

    // Get the connected socket.
    Get Create (RefClass(cComChilkatSocket)) To hoSock
    If (Not(IsComObjectCreated(hoSock))) Begin
        Send CreateComObject of hoSock
    End
    Get ComLoadTaskResult Of hoSock vTask To iSuccess
    Send Destroy of hoTask

    // We're acting as a temporary web server to receive this one redirected HTTP request..
    // Read the start line of the request.. (i.e. the "POST /myapp/ HTTP/1.1")
    Get ComReceiveUntilMatch Of hoSock (character(13)) + (character(10)) To sStartLine
    Get ComLastMethodSuccess Of hoSock To bTemp1
    If (bTemp1 <> True) Begin
        Get ComLastErrorText Of hoSock To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    // Read the request header.
    Get ComReceiveUntilMatch Of hoSock (character(13)) + (character(10)) + (character(13)) + (character(10)) To sRequestHeader
    Get ComLastMethodSuccess Of hoSock To bTemp1
    If (bTemp1 <> True) Begin
        Get ComLastErrorText Of hoSock To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    Showln sRequestHeader
    Showln "----"

    // Read the body.
    // The body will contain "id_token= eyJ......"
    Get Create (RefClass(cComChilkatStringBuilder)) To hoSbRequestBody
    If (Not(IsComObjectCreated(hoSbRequestBody))) Begin
        Send CreateComObject of hoSbRequestBody
    End
    Get pvComObject of hoSbRequestBody to vSbRequestBody
    Get ComReceiveSb Of hoSock vSbRequestBody To iSuccess
    If (iSuccess = False) Begin
        Get ComLastErrorText Of hoSock To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    Get ComGetAsString Of hoSbRequestBody To sTemp1
    Showln sTemp1

    // Given that we're acting as a web server, we must send a response..
    // We can now send our HTTP response.
    Get Create (RefClass(cComChilkatStringBuilder)) To hoSbResponseHtml
    If (Not(IsComObjectCreated(hoSbResponseHtml))) Begin
        Send CreateComObject of hoSbResponseHtml
    End
    Get ComAppend Of hoSbResponseHtml "<html><body><p>Thank you!</b></body</html>" To iSuccess

    Get Create (RefClass(cComChilkatStringBuilder)) To hoSbResponse
    If (Not(IsComObjectCreated(hoSbResponse))) Begin
        Send CreateComObject of hoSbResponse
    End
    Get ComAppend Of hoSbResponse "HTTP/1.1 200 OK" + (character(13)) + (character(10)) To iSuccess
    Get ComAppend Of hoSbResponse "Content-Length: " To iSuccess
    Get ComLength Of hoSbResponseHtml To iTemp1
    Get ComAppendInt Of hoSbResponse iTemp1 To iSuccess
    Get ComAppend Of hoSbResponse (character(13)) + (character(10)) To iSuccess
    Get ComAppend Of hoSbResponse "Content-Type: text/html" + (character(13)) + (character(10)) To iSuccess
    Get ComAppend Of hoSbResponse (character(13)) + (character(10)) To iSuccess
    Get pvComObject of hoSbResponseHtml to vSbResponseHtml
    Get ComAppendSb Of hoSbResponse vSbResponseHtml To iSuccess

    Get ComGetAsString Of hoSbResponse To sTemp1
    Get ComSendString Of hoSock sTemp1 To iSuccess
    Get ComClose Of hoSock 50 To iSuccess

    // Get the id_token from the sbRequestBody that we just received.
    // (Remember, we're acting as the web server, thus we received the redirect request..)
    Get Create (RefClass(cComChilkatHashtable)) To hoHashTab
    If (Not(IsComObjectCreated(hoHashTab))) Begin
        Send CreateComObject of hoHashTab
    End
    Get ComGetAsString Of hoSbRequestBody To sTemp1
    Get ComAddQueryParams Of hoHashTab sTemp1 To iSuccess

    // See https://docs.microsoft.com/en-us/azure/active-directory/develop/id-tokens#validating-an-id-token
    // for more information about ID tokens..
    Get ComLookupStr Of hoHashTab "id_token" To sIdToken

    Get Create (RefClass(cComChilkatJwt)) To hoJwt
    If (Not(IsComObjectCreated(hoJwt))) Begin
        Send CreateComObject of hoJwt
    End

    // Let's see if the time constraints, if any, are valid.
    // The above JWT was created on the afternoon of 16-May-2016, with an expiration of 1 hour.
    // If the current system time is before the "nbf" time, or after the "exp" time,
    // then IsTimeValid will return false/0.
    // Also, we'll allow a leeway of 60 seconds to account for any clock skew.
    // Note: If the token has no "nbf" or "exp" claim fields, then IsTimeValid is always true.
    Move 60 To iLeeway
    Get ComIsTimeValid Of hoJwt sIdToken iLeeway To iBTimeValid
    Showln "time constraints valid: " iBTimeValid

    // Now let's recover the original claims JSON (the payload).
    Get ComGetPayload Of hoJwt sIdToken To sPayload
    // The payload will likely be in compact form:
    Showln sPayload

    // We can format for human viewing by loading it into Chilkat's JSON object
    // and emit.
    Get Create (RefClass(cComChilkatJsonObject)) To hoJson
    If (Not(IsComObjectCreated(hoJson))) Begin
        Send CreateComObject of hoJson
    End
    Get ComLoad Of hoJson sPayload To iSuccess
    Set ComEmitCompact Of hoJson To False
    Get ComEmit Of hoJson To sTemp1
    Showln sTemp1

    // Sample output:

    // {
    //   "aud": "f125d695-c50e-456e-a579-a486f06d1213",
    //   "iss": "https://login.microsoftonline.com/6d8ddd66-68d1-43b0-af5c-e31b4b7dd5cd/v2.0",
    //   "iat": 1626535322,
    //   "nbf": 1626535322,
    //   "exp": 1626539222,
    //   "aio": "AWQAm/8TAAAAHQncmY0VvhgyMIhfleHX3DjsGfmlPM1CopkJ3mPnBUnCxrJ0ubruaACEhwGO7NsoHBhqFEzRzPxOq7MtuGVFsql+qJKZx8vQCszKYEPX9Wb3b5+d5KJTABHCIH48bTFd",
    //   "idp": "https://sts.windows.net/9188040d-6c67-4c5b-b112-36a304b66dad/",
    //   "nonce": "1519043321",
    //   "rh": "0.ARgAZt2NbdFosEOvXOMbS33VzZXWJfEOxW5FpXmkhvBtEhMYALQ.",
    //   "sub": "RMIZlHJ7hfsJmL8Qq3h6M0nPi4g-HEavnAFgxzaT2KM",
    //   "tid": "6d8ddd66-68d1-43b0-af5c-e31b4b7dd5cd",
    //   "uti": "-BXGHxvfREW-r9HI5NBiAA",
    //   "ver": "2.0"
    // }

    // We can recover the original JOSE header in the same way:
    Get ComGetHeader Of hoJwt sIdToken To sJoseHeader
    // The payload will likely be in compact form:
    Showln sJoseHeader

    // We can format for human viewing by loading it into Chilkat's JSON object
    // and emit.
    Get Create (RefClass(cComChilkatJsonObject)) To hoJsonJoseHeader
    If (Not(IsComObjectCreated(hoJsonJoseHeader))) Begin
        Send CreateComObject of hoJsonJoseHeader
    End
    Get ComLoad Of hoJsonJoseHeader sJoseHeader To iSuccess
    Set ComEmitCompact Of hoJsonJoseHeader To False
    Get ComEmit Of hoJsonJoseHeader To sTemp1
    Showln sTemp1

    // Sample output:

    // {
    //   "typ": "JWT",
    //   "alg": "RS256",
    //   "kid": "nOo3ZDrODXEK1jKWhXslHR_KXEg"
    // }

    // Finally, we need to fetch the JSON Web Key Sets from the jwks_uri
    // and use it to verify the id_token's RSA signature.
    Get Create (RefClass(cComChilkatStringBuilder)) To hoSbJwks
    If (Not(IsComObjectCreated(hoSbJwks))) Begin
        Send CreateComObject of hoSbJwks
    End
    Get Create (RefClass(cComChilkatHttp)) To hoHttp
    If (Not(IsComObjectCreated(hoHttp))) Begin
        Send CreateComObject of hoHttp
    End
    Get pvComObject of hoSbJwks to vSbJwks
    Get ComQuickGetSb Of hoHttp sJwks_uri vSbJwks To iSuccess
    If (iSuccess = False) Begin
        Get ComLastErrorText Of hoHttp To sTemp1
        Showln sTemp1
        Procedure_Return
    End

    Get Create (RefClass(cComChilkatJsonObject)) To hoJwkset
    If (Not(IsComObjectCreated(hoJwkset))) Begin
        Send CreateComObject of hoJwkset
    End
    Get pvComObject of hoSbJwks to vSbJwks
    Get ComLoadSb Of hoJwkset vSbJwks To iSuccess
    Set ComEmitCompact Of hoJwkset To False
    Get ComEmit Of hoJwkset To sTemp1
    Showln sTemp1

    // A sample jwkset:

    // {
    //   "keys": [
    //     {
    //       "kty": "RSA",
    //       "use": "sig",
    //       "kid": "nOo3ZDrODXEK1jKWhXslHR_KXEg",
    //       "x5t": "nOo3ZDrODXEK1jKWhXslHR_KXEg",
    //       "n": "oaLLT9hkcSj ... NVrZdUdTBQ",
    //       "e": "AQAB",
    //       "x5c": [
    //         "MIIDBTC ... MRku44Dw7R"
    //       ],
    //       "issuer": "https://login.microsoftonline.com/6d8ddd66-68d1-43b0-af5c-e31b4b7dd5cd/v2.0"
    //     },
    //     {
    //       "kty": "RSA",
    //       "use": "sig",
    //       "kid": "l3sQ-50cCH4xBVZLHTGwnSR7680",
    //       "x5t": "l3sQ-50cCH4xBVZLHTGwnSR7680",
    //       "n": "sfsXMXW ... AYkwb6xUQ",
    //       "e": "AQAB",
    //       "x5c": [
    //         "MIIDBTCCA ... BWrh+/vJ"
    //       ],
    //       "issuer": "https://login.microsoftonline.com/6d8ddd66-68d1-43b0-af5c-e31b4b7dd5cd/v2.0"
    //     },
    //     {
    //       "kty": "RSA",
    //       "use": "sig",
    //       "kid": "DqUu8gf-nAgcyjP3-SuplNAXAnc",
    //       "x5t": "DqUu8gf-nAgcyjP3-SuplNAXAnc",
    //       "n": "1n7-nWSL ... V3pFWhQ",
    //       "e": "AQAB",
    //       "x5c": [
    //         "MIIC8TC ... 9pIcnkPQ=="
    //       ],
    //       "issuer": "https://login.microsoftonline.com/6d8ddd66-68d1-43b0-af5c-e31b4b7dd5cd/v2.0"
    //     },
    //     {
    //       "kty": "RSA",
    //       "use": "sig",
    //       "kid": "OzZ5Dbmcso9Qzt2ModGmihg30Bo",
    //       "x5t": "OzZ5Dbmcso9Qzt2ModGmihg30Bo",
    //       "n": "01re9a2BU ... 5OzQ6Q",
    //       "e": "AQAB",
    //       "x5c": [
    //         "MIIC8TC ... YmwJ6sDdRvQ=="
    //       ],
    //       "issuer": "https://login.microsoftonline.com/6d8ddd66-68d1-43b0-af5c-e31b4b7dd5cd/v2.0"
    //     }
    //   ]
    // }

    // We should have an RSA key with kid matching the kid from the joseHeader..
    Get ComStringOf Of hoJsonJoseHeader "kid" To sKid

    // Find the RSA key with the specified key id
    Get ComFindRecord Of hoJwkset "keys" "kid" sKid True To vJwk
    If (IsComObject(vJwk)) Begin
        Get Create (RefClass(cComChilkatJsonObject)) To hoJwk
        Set pvComObject Of hoJwk To vJwk
    End
    Get ComLastMethodSuccess Of hoJwkset To bTemp1
    If (bTemp1 = False) Begin
        Showln "Failed to find a matching RSA key in the JWK key set..."
        Procedure_Return
    End

    Get Create (RefClass(cComChilkatPublicKey)) To hoPubkey
    If (Not(IsComObjectCreated(hoPubkey))) Begin
        Send CreateComObject of hoPubkey
    End

    Get ComEmit Of hoJwk To sTemp1
    Get ComLoadFromString Of hoPubkey sTemp1 To iSuccess
    If (iSuccess = False) Begin
        Get ComLastErrorText Of hoPubkey To sTemp1
        Showln sTemp1
        Get ComEmit Of hoJwk To sTemp1
        Showln sTemp1
    End
    Else Begin
        Get pvComObject of hoPubkey to vPubkey
        Get ComVerifyJwtPk Of hoJwt sIdToken vPubkey To iVerified
        Showln "Verified: " iVerified
    End

    Send Destroy of hoJwk


End_Procedure

 

© 2000-2024 Chilkat Software, Inc. All Rights Reserved.