🛡️2FA with Python.
Tags: python, security, tutorial
Published: 2021-12-22 06:07:31

## What is 2FA and why 2FA?🤔

2FA stands for two factor authentication. It adds an extra layer of security other than password. The user must enter a 2FA code along with password in order to sign in. 2FA codes can be generated in two ways, time based codes and counter based codes.

### Advantages of 2FA over E-Mail or SMS verification:

- **No network required**: *2FA codes can be generated offline*.
- 🛡️ **Better security**.

### Time based codes vs counter based code.

| Time based codes                                     | Counter based codes                                          |
| :--------------------------------------------------- | :----------------------------------------------------------- |
| Time based codes changes depending on time. 🕖        | Counter based codes change depending on number of successful sign-in(s). ✔️ |
| No need of adding counter every time in client side. | After every successful login, counter must be increased by one in server side as well as client side. |


![2FA flowchart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vwup95vrhfnda20mh4qq.png)

## 2FA with Python

### Requirements

- **[onetimepass python package](https://pypi.org/project/onetimepass/)** *(Can be installed using the command: `pip install onetimepass`)*.
- **Your favourite authenticator app** *(Example: Google authenticator, Microsoft authenticator)*.

### Let's start!👀

For both time based codes and counter based code, a secret string is securely shared with the authenticator app while setting up 2FA. All codes are generated based on this secret string. This string is not case sensitive.

#### 🕖Time based codes

Let us now, write a simple Python script to understand how time based 2FA works!

```python
from onetimepass import valid_totp
from secrets import choice


def generate_secret():  # Function to return a random string with length 16.
    secret = ''
    while len(secret) < 16:
        secret += choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567')
    return secret


secret = generate_secret()
print('Enter the following secret in your authenticator app: ', secret)
print("""
Instructions for saving this secret it Google Authenticator:
1. Open Google Authenticator.
2. Click plus icon at the right bottom.
3. Click Enter a setup key.
4. Enter an Account name of your choice and enter the secret provided above.
5. Click Add.
""")
while True:
    otp = int(input('Please enter the otp generated by your authenticator app: '))
    authenticated = valid_totp(otp, secret)
    if authenticated:
        print('Correct otp, Authenticated!')
    elif not authenticated:
        print('Wrong otp, please try again.')
```

#### ✔️ Counter based codes

Here is a complete Python script to understand how counter based 2FA works!

```python
from onetimepass import valid_hotp
from secrets import choice


def generate_secret():  # Function to return a random string with length 16.
    secret = ''
    while len(secret) < 16:
        secret += choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567')
    return secret


secret = generate_secret()
print('Enter the following secret in your authenticator app: ', secret)
print("""
Instructions for saving this secret it Google Authenticator:
1. Open Google Authenticator.
2. Click plus icon at the right bottom.
3. Click Enter a setup key.
4. Enter an Account name of your choice and enter the secret provided above.
5. Click Add.
""")
while True:
    counter = 0
    otp = int(input('Please enter the otp generated by your authenticator app: '))
    authenticated = valid_hotp(otp, secret)
    if authenticated:
        print('Correct otp, Authenticated!')
        counter += 1
    elif not authenticated:
        print('Wrong otp, please try again.')
```

**Thank you**! Leave a comment and a like if you find this article useful :-)

**[About me](https://jothin.tech/)**

[![](https://jothin.tech/favicon.png)](https://jothin.tech)

Original article: https://blog.jothin.tech/2fa-with-python

Edit: Thanks to @amoir18 for reporting a mistake.