Sample code for 30+ languages & platforms
PureBasic

SSH Auth Failure Reason (AuthenticatePwPk)

See more SSH Examples

Demonstrates how to determine why authentication failed when a server requires both a password and a private key. If AuthenticatePwPk fails, GetLastJsonData returns diagnostic JSON whose authResult and authFailReason members reveal which factor was at fault.

Background: With multi-factor SSH, a plain failure is ambiguous — the key could be wrong, the password could be wrong, or both. The diagnostic JSON resolves that: it reports Key is incorrect when the key fails, or a partialAuthResult showing the key succeeded before Password is incorrect. Note the ordering consequence: if the key is rejected, authentication never reaches the password check, so you cannot yet know whether the password is also wrong. Passwords and passphrases are never included in this JSON, so it is safe to log.

Chilkat PureBasic Downloads

PureBasic
IncludeFile "CkSshKey.pb"
IncludeFile "CkJsonObject.pb"
IncludeFile "CkSsh.pb"

Procedure ChilkatExample()

    success.i = 0

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

    ;  Demonstrates how to determine why authentication failed when a server requires BOTH a
    ;  password and a private key.  Was the private key wrong, or the password?

    ;  Load the private key used for authentication.
    key.i = CkSshKey::ckCreate()
    If key.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    ;  The key password is not hard-coded in a real application; obtain it from a secure source.
    CkSshKey::setCkPassword(key, "myKeyPassword")

    privKeyText.s = CkSshKey::ckLoadText(key,"qa_data/my_private_key_file")
    If CkSshKey::ckLastMethodSuccess(key) = 0
        Debug CkSshKey::ckLastErrorText(key)
        CkSshKey::ckDispose(key)
        ProcedureReturn
    EndIf

    success = CkSshKey::ckFromOpenSshPrivateKey(key,privKeyText)
    If success = 0
        Debug CkSshKey::ckLastErrorText(key)
        CkSshKey::ckDispose(key)
        ProcedureReturn
    EndIf

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

    port.i = 22
    success = CkSsh::ckConnect(ssh,"ssh.example.com",port)
    If success = 0
        Debug CkSsh::ckLastErrorText(ssh)
        CkSshKey::ckDispose(key)
        CkSsh::ckDispose(ssh)
        ProcedureReturn
    EndIf

    ;  Normally you would not hard-code the password in source.  You should instead obtain it
    ;  from an interactive prompt, environment variable, or a secrets vault.
    password.s = "mySshPassword"

    ;  Authenticate using both a password and a private key.
    success = CkSsh::ckAuthenticatePwPk(ssh,"mySshLogin",password,key)
    If success
        Debug "Authentication is successful!"
        CkSshKey::ckDispose(key)
        CkSsh::ckDispose(ssh)
        ProcedureReturn
    EndIf

    ;  Authentication failed.  The diagnostic JSON explains which factor was at fault.
    json.i = CkJsonObject::ckCreate()
    If json.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkSsh::ckGetLastJsonData(ssh,json)
    CkJsonObject::setCkEmitCompact(json, 0)

    ;  If the key is correct but the password is wrong:
    ;  {
    ;    "public_key_type": "rsa",
    ;    "partialAuthResult": "publickey success. continue to authenticate with password...",
    ;    "authResult": "failed",
    ;    "authFailReason": "Password is incorrect"
    ;  }
    ;  
    ;  If the key is incorrect.  Whether the password is also wrong is unknown, because
    ;  authentication never got far enough to check it:
    ;  {
    ;    "public_key_type": "rsa",
    ;    "authResult": "failed",
    ;    "authFailReason": "Key is incorrect"
    ;  }

    Debug "authResult: " + CkJsonObject::ckStringOf(json,"authResult")
    Debug "authFailReason: " + CkJsonObject::ckStringOf(json,"authFailReason")


    CkSshKey::ckDispose(key)
    CkSsh::ckDispose(ssh)
    CkJsonObject::ckDispose(json)


    ProcedureReturn
EndProcedure