Skip navigation
Documentation

Duo Two-Factor Authentication API for Applications

Last Updated: October 21st, 2021

Contents

Add two-factor authentication and self-service user enrollment to your application using Duo's Auth API and your own user interface.

Overview

This solution guide will help you use Duo's Auth API to add two-factor authentication with your custom user interface to SaaS or on-premises applications.

As part of Duo's enrollment process, users will install the Duo Mobile app on their iOS or Android devices and activate it for use with our service, and then use the application to approve login verification requests after completing primary authentication.

This guide assumes that you'll store a two-factor authentication "status" for each user — for example, adding a "Require 2FA?" column to the users table in your database. You'll set this flag to "true" once the user enables Duo authentication.

Python

The examples in this guide use the duo_client_python client library. Clone the repository (and set your Auth API application's IKEY, SKEY, and HOST as environment variables) if you want to copy and paste the example code.

Treat your secret key like a password

The security of your Duo application is tied to the security of your secret key (skey). Secure it as you would any sensitive credential. Don't share it with unauthorized individuals or email it to anyone under any circumstances!

$ git clone https://github.com/duosecurity/duo_client_python
$ cd duo_client_python
$ export IKEY= # your Auth API application's "Integration key"
$ export SKEY= # your Auth API application's "Secret key"
$ export HOST= # your Auth API application's "API hostname"

Then call the /check endpoint to make sure everything is working:

$ python -m duo_client.client --ikey $IKEY --skey $SKEY --host $HOST \
  --path /auth/v2/check --method GET
200 OK
{
  "response": {
    "time": 1361213173
  },
  "stat": "OK"
}

Enrollment

Before using Duo to authenticate a user, the user and an associated device must enroll in Duo's service.

When a new user — that is, a user Duo doesn't know about yet — wants to enable two-factor authentication, call /enroll. This returns the URL of a QR code that contains a unique enrollment code that corresponds to your Duo instance and Auth API application. The user scans the QR code with Duo Mobile to enroll. The user will see a new entry appear in Duo Mobile:

First Account Entry in Duo Mobile

The name of the account comes from the name of your Duo account. Upload your logo using the Duo Admin Panel.

You can optionally pass the user's username to the /enroll endpoint. This stores the username in Duo's database so you can later authenticate the user with Duo by referencing this value. If you don't pass a username, store the returned user_id in your database and use that identifier in future API calls.

A call to /enroll looks like this:

$ python -m duo_client.client --ikey $IKEY --skey $SKEY --host $HOST \
  --path /auth/v2/enroll --method POST username=narroway
200 OK
{
  "response": {
    "activation_barcode": "https://api-12345678.duosecurity.com/frame/qr?value=duo%3A%2F%2FbcQirraSbgdQEY3wMjqS-YXBpLWZpcnN0LnRlc3QuZHVvc2VjdXJpdHkuY29t",
    "activation_code": "duo://bcQirraSbgdQEY3wMjqS-YXBpLWZpcnN0LnRlc3QuZHVvc2VjdXJpdHkuY29t",
    "expiration": 1361290076,
    "user_id": "DUYWPFNY2VCCHD0SI5EC",
    "username": "narroway"
  },
  "stat": "OK"
}

The returned activation_barcode is the URL of a QR code. Instruct your users to install Duo Mobile (for iPhone or Android) and then scan the QR code. Duo Mobile uses your phone's camera to scan the enrollment QR code, adding the account to Duo Mobile and activating it for Duo Push and Duo Mobile passcode generation. Your enrollment interface might look something like this:

Enrollment Example

To check if the user successfully scanned the QR code, call /enroll_status with the user's Duo user_id and the Duo activation_code.

$ python -m duo_client.client --ikey $IKEY --skey $SKEY --host $HOST \
  --path /auth/v2/enroll_status --method POST user_id=DUYWPFNY2VCCHD0SI5EC \
  activation_code=duo://8LIRa5danrICkhHtkLxi-cKLu2DWzDYCmBwBHY2YzW5ZYnYaRxA
200 OK
{
  "response": "success",
  "stat": "OK"
}

Confirming that response is "success" is highly recommended to ensure that the user's authenticator is fully functional before requiring its use for authentication.

Once the Duo Mobile enrollment process is successful, we recommend presenting the user with backup authentication methods before requiring Duo for future logins. See Backup Methods for more information.

When the user completes Duo enrollment, store this fact in your user database so you know to require two-factor authentication during future logins.

Authentication

Primary Authentication

Your application should continue to handle primary authentication in whatever manner you used before adding Duo. Usually this means checking the user's username and password against your database or identity store.

If the user's primary credentials are correct, consult your application's database to see whether this user has completed enrollment in (and thus should be challenged with) Duo authentication as a second factor. If they haven't enrolled, either prompt them to enroll (if two-factor authentication isn't optional and you're relying on trust-on-first-use) or simply let them in to the application.

If your primary identity store indicates the user completed Duo enrollment and secondary authentication is necessary, proceed to Duo authentication via the API.

Secondary (Duo) Authentication

Call /preauth to get the user's enrollment status and device information from Duo. For example:

$ python -m duo_client.client --ikey $IKEY --skey $SKEY --host $HOST \
  --path /auth/v2/preauth --method POST username=narroway
200 OK
{
  "response": {
    "devices": [
      {
        "capabilities": [
          "auto", 
          "push", 
          "sms", 
          "phone", 
          "mobile_otp"
        ],
        "device": "DPL8XE3Q1KDDH99KRRLS",
        "display_name": "Google Pixel 5",
        "name": "Pixel 5",
        "number": "734-555-2233",
        "type": "phone"
      }
    ],
    "result": "auth",
    "status_msg": "Account is active"
  },
  "stat": "OK"
}

The result will be "auth" if the user exists in Duo, and devices will be a list of authentication devices (although in this case the list will only contain one device). If result is "enroll", you can enter the Enrollment flow, to give the user the opportunity to register a device for two-factor authentication during the login process. Also see /preauth documentation for other possible result values.

The capabilities array will contain "push" since both iPhone and Android support Duo Push. Note that while "passcode" will never be returned in this array, submitting a passcode is always allowed.

After calling /preauth, you may want to show information about the authentication device and let the user choose how to authenticate. For example:

Secondary Authentication Prompt

This interface is completely up to you. You can show all available authentication options or only allow one. You might Push automatically and then allow a passcode as a backup. You'll probably also want to show options for any backup methods you choose to implement.

Once you know which authentication method to use, call /auth, either to use Duo Push, call the device, or validate a passcode.

Duo Push

Duo Push is the most convenient method for users with Android and iOS phones or tablets. It sends a push notification to the user's device, which invokes the Duo Mobile app and prompts the user to approve the login request.

Duo Mobile Request Approval

The following example calls /auth, specifies sending a push to the first capable device associated with the user, and requests async in order to later poll for status:

$ python -m duo_client.client --ikey $IKEY --skey $SKEY --host $HOST \
  --path /auth/v2/auth --method POST username=narroway device=auto \
  factor=push ipaddr=10.211.144.186 async=1
200 OK
{
  "response": {
    "txid": "69ea7736-2041-4454-83c0-3a0fbb0564fc"
  },
  "stat": "OK"
}

Your application should long-poll using the /auth_status endpoint to check if the user has approved the authentication request. For example:

$ python -m duo_client.client --ikey $IKEY --skey $SKEY --host $HOST \
  --path /auth/v2/auth_status --method GET txid=69ea7736-2041-4454-83c0-3a0fbb0564fc
200 OK
{
  "response": {
    "result": "waiting",
    "status": "pushed",
    "status_msg": "Pushed a login request to your phone..."
  },
  "stat": "OK"
}

Call the endpoint again and then approve the login request:

$ python -m duo_client.client --ikey $IKEY --skey $SKEY --host $HOST \
  --path /auth/v2/auth_status --method GET txid=69ea7736-2041-4454-83c0-3a0fbb0564fc
200 OK
{
  "response": {
    "result": "allow",
    "status": "allow",
    "status_msg": "Success. Logging you in..."
  },
  "stat": "OK"
}

Only log the user in when result is "allow". See the /auth documentation to learn how to handle other responses.

Passcode

If the user enters a passcode, use /auth to validate it. This will return immediately so there's no reason to use async. Do not specify a device.

$ python -m duo_client.client --ikey $IKEY --skey $SKEY --host $HOST \
  --path /auth/v2/auth --method POST username=narroway factor=passcode passcode=123456

If the passcode is valid the following is returned:

200 OK
{
  "stat": "OK",
  "response": {
    "result": "allow",
    "status": "allow",
    "status_msg": "Success. Logging you in..."
  }
}

See the /auth documentation to learn how to handle other responses.

Backup Methods

Once two-factor authentication is enabled for a user's account, the user will need the associated smartphone in order to authenticate. If the user's phone is unavailable the user will not be able to login. The Duo secrets are only stored on the specific hardware device used during activation, and by design they are not backed up anywhere — even if users back up their phone data using Apple or Android services. When a user upgrades to a new device an alternative authentication method will be required.

Application-Generated Backup Code

Your application can generate a one-time use backup code, associate it with the user's account, and display it to the user. This puts your application completely in control of the backup method, entirely independent from Duo.

Best Practices

Usernames

If your service allows your users to change their usernames at any point (or if username privacy is a concern), you may want Duo to store anonymous identifiers instead of usernames. If you don't pass a username to /enroll it will return an anonymous identifier for you to store in your users database and use in future calls. You'll probably also want to use the display_username when calling /auth so that the user sees their actual username on the login request screen.

Remember This Browser

Your application may already support the ability for a user to stay logged in even after the user closes the browser. We recommend you consider offering your users the ability to remember that a specific browser was successfully used for two-factor authentication, and not to challenge for two-factor authentication again from that same browser. If the user decides to remember the browser for purposes of two-factor authentication then the application would set a second cookie to track this state.

This does reduce security in favor of usability. Users are only prompted to perform two-factor authentication when logging in from unknown browsers, or when their two-factor authentication cookie has expired. You can consider remembering a browser indefinitely or for a specified time period (30 days is common).

Troubleshooting

Need some help? Take a look at our Auth API Knowledge Base articles or Community discussions. For further assistance, contact Support.