Sample code for 30+ languages & platforms
PureBasic

Duo Auth API - Async Auth

See more Duo Auth MFA Examples

If you enable async, then your application will be able to retrieve real-time status updates from the authentication process, rather than receiving no information until the process is complete.

Chilkat PureBasic Downloads

PureBasic
IncludeFile "CkHttpResponse.pb"
IncludeFile "CkHttp.pb"
IncludeFile "CkStringBuilder.pb"
IncludeFile "CkJsonObject.pb"
IncludeFile "CkHttpRequest.pb"

Procedure ChilkatExample()

    success.i = 0

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

    integrationKey.s = "DIMS3V5QDVG9J9ABRXC4"
    secretKey.s = "HWVQ46nubLBxhnRlKddTltWIi3hL0fIQF2qTvLab"

    http.i = CkHttp::ckCreate()
    If http.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkHttp::setCkAccept(http, "application/json")

    ; Use your own hostname here:
    url.s = "https://api-a03782e1.duosecurity.com/auth/v2/auth"

    ; This example requires Chilkat v9.5.0.89 or greater because Chilkat will automatically
    ; generate and send the HMAC signature for the requires based on the integration key and secret key.
    CkHttp::setCkLogin(http, integrationKey)
    CkHttp::setCkPassword(http, secretKey)

    req.i = CkHttpRequest::ckCreate()
    If req.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkHttpRequest::ckAddParam(req,"username","matt")
    CkHttpRequest::ckAddParam(req,"factor","push")
    ; The device ID can be obtained from the preauth response.  See Duo Preauth Example
    CkHttpRequest::ckAddParam(req,"device","DP6GYVTQ5NK82BMR851F")
    ; Add the async param to get an immediate response, then periodically check for updates to find out when the MFA authentication completes for fails.
    CkHttpRequest::ckAddParam(req,"async","1")

    CkHttpRequest::setCkHttpVerb(req, "POST")
    CkHttpRequest::setCkContentType(req, "application/x-www-form-urlencoded")

    resp.i = CkHttpResponse::ckCreate()
    If resp.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkHttp::ckHttpReq(http,url,req,resp)
    If success = 0
        Debug CkHttp::ckLastErrorText(http)
        CkHttp::ckDispose(http)
        CkHttpRequest::ckDispose(req)
        CkHttpResponse::ckDispose(resp)
        ProcedureReturn
    EndIf

    Debug "status code = " + Str(CkHttpResponse::ckStatusCode(resp))

    json.i = CkJsonObject::ckCreate()
    If json.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkJsonObject::ckLoad(json,CkHttpResponse::ckBodyStr(resp))
    CkJsonObject::setCkEmitCompact(json, 0)
    Debug CkJsonObject::ckEmit(json)

    If CkHttpResponse::ckStatusCode(resp) <> 200
        CkHttp::ckDispose(http)
        CkHttpRequest::ckDispose(req)
        CkHttpResponse::ckDispose(resp)
        CkJsonObject::ckDispose(json)
        ProcedureReturn
    EndIf

    ; Sample successful output:

    ; status code = 200

    ; {
    ;   "stat": "OK",
    ;   "response": {
    ;     "txid": "45f7c92b-f45f-4862-8545-e0f58e78075a"
    ;   }
    ; }

    txid.s = CkJsonObject::ckStringOf(json,"response.txid")

    ; Use your own hostname here:
    sbUrl.i = CkStringBuilder::ckCreate()
    If sbUrl.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkStringBuilder::ckAppend(sbUrl,"https://api-a03782e1.duosecurity.com/auth/v2/auth_status?txid=")
    CkStringBuilder::ckAppend(sbUrl,txid)
    url.s = CkStringBuilder::ckGetAsString(sbUrl)

    Debug "Auth status URL: " + url

    sbResult.i = CkStringBuilder::ckCreate()
    If sbResult.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    responseStatus.s
    responseStatus_msg.s

    ; Wait for a response...
    i.i = 0
    maxWaitIterations.i = 100
    While i < maxWaitIterations
        ; Wait 3 seconds.
        CkHttp::ckSleepMs(http,3000)

        Debug "Polling..."

        success = CkHttp::ckHttpNoBody(http,"GET",url,resp)
        If success = 0
            Debug CkHttp::ckLastErrorText(http)
            CkHttp::ckDispose(http)
            CkHttpRequest::ckDispose(req)
            CkHttpResponse::ckDispose(resp)
            CkJsonObject::ckDispose(json)
            CkStringBuilder::ckDispose(sbUrl)
            CkStringBuilder::ckDispose(sbResult)
            ProcedureReturn
        EndIf

        If CkHttpResponse::ckStatusCode(resp) <> 200
            Debug "error status code = " + Str(CkHttpResponse::ckStatusCode(resp))
            Debug CkHttpResponse::ckBodyStr(resp)
            Debug "Failed."
            CkHttp::ckDispose(http)
            CkHttpRequest::ckDispose(req)
            CkHttpResponse::ckDispose(resp)
            CkJsonObject::ckDispose(json)
            CkStringBuilder::ckDispose(sbUrl)
            CkStringBuilder::ckDispose(sbResult)
            ProcedureReturn
        EndIf

        ; Sample response:

        ; 	{
        ; 	  "stat": "OK",
        ; 	  "response": {
        ; 	    "result": "waiting",
        ; 	    "status": "pushed",
        ; 	    "status_msg": "Pushed a login request to your phone..."
        ; 	  }
        ; 	}

        CkJsonObject::ckLoad(json,CkHttpResponse::ckBodyStr(resp))

        ; The responseResult can be "allow", "deny", or "waiting"
        CkStringBuilder::ckClear(sbResult)
        CkJsonObject::ckStringOfSb(json,"response.result",sbResult)
        responseStatus = CkJsonObject::ckStringOf(json,"response.status")
        responseStatus_msg = CkJsonObject::ckStringOf(json,"response.status_msg")

        Debug CkStringBuilder::ckGetAsString(sbResult)
        Debug responseStatus
        Debug responseStatus_msg
        Debug ""

        If CkStringBuilder::ckContentsEqual(sbResult,"waiting",1) = 1
            i = i + 1
        Else
            ; Force loop exit..
            i = maxWaitIterations
        EndIf

    Wend

    Debug "Finished."


    CkHttp::ckDispose(http)
    CkHttpRequest::ckDispose(req)
    CkHttpResponse::ckDispose(resp)
    CkJsonObject::ckDispose(json)
    CkStringBuilder::ckDispose(sbUrl)
    CkStringBuilder::ckDispose(sbResult)


    ProcedureReturn
EndProcedure