PLATFORM
  • Tails

    Create websites with TailwindCSS

  • Blocks

    Design blocks for your website

  • Wave

    Start building the next great SAAS

  • Pines

    Alpine & Tailwind UI Library

  • Auth

    Plug'n Play Authentication for Laravel

  • Designer comingsoon

    Create website designs with AI

  • DevBlog comingsoon

    Blog platform for developers

  • Static

    Build a simple static website

  • SaaS Adventure

    21-day program to build a SAAS

Question By
Solved

Google Authenticator

Solved
brianh

Aug 16th, 2023 11:48 AM

Hi Guys,

So bit of a deep dive question, but thought it would be best to ask this awesome community.

In my SaaS app, I have an a server that I want to get information from using an api. In order to be able to use the server apis, it will always be necessary to have an access token so that it can be executed correctly. For this, I have to generate a token using a post request to the api https://server/restapi/v2.0/auth. The body of this post request would be raw JSON as follows: { "grantTye":"password", "userAuthDevice":{}, "username": "username", "password": "password", "totp": "" }

totp stands for a otp code that is given to me using the google authenticator app. The reponse will contain my token. I have to rerun the auth post request every 20 minutes. How can I do this automatically within my SaaS application without having to have the user provide the OTP every 20 minutes? Is that even possible?

bobbyiliev

Aug 17th, 2023 12:51 PM

Hi there,

What is the API in question that you are trying to consume? In most cases there should be there should be an option for a long lived refresh token, you could check if the server supports the OAuth 2.0 protocol or a similar authentication mechanism that allows the use of refresh tokens. Refresh tokens can be used to obtain new access tokens without requiring the user to log in again. This would allow you to maintain a session without the need to enter the TOTP every time.

If this is indeed the only way of doing it, here is how you might be able to achieve it:

1. Install Guzzle HTTP

Make sure the Guzzle HTTP library is installed, as Laravel's HTTP client uses it under the hood:

composer require guzzlehttp/guzzle

2. Create an AuthenticationService

Consider creating a dedicated service class to handle authentication and token management. This will keep your code organized and easier to maintain.

<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;

class AuthenticationService
{
    private $token;

    public function authenticate($username, $password, $totp)
    {
        $response = Http::post('https://server/restapi/v2.0/auth', [
            'grantType' => 'password',
            'userAuthDevice' => new \stdClass(),
            'username' => $username,
            'password' => $password,
            'totp' => $totp,
        ]);

        if ($response->successful()) {
            $this->token = $response->json()['token'];
            return $this->token;
        }

        throw new \Exception('Authentication failed');
    }

    public function getToken()
    {
        return $this->token;
    }

    // Additional methods for refreshing the token if needed
}

3. Schedule the Token Renewal

If you need to refresh the token every 20 minutes, consider using Laravel's task scheduling to run a command that refreshes the token.

First, create a console command to refresh the token:

php artisan make:command RefreshToken

In your command class, inject the AuthenticationService and call the method to refresh the token:

public function handle(AuthenticationService $authService)
{
    // Logic to refresh the token
    $authService->refreshToken();
}

Then, in your App\Console\Kernel.php, schedule the command to run every 20 minutes:

protected function schedule(Schedule $schedule)
{
    $schedule->command('refresh:token')->everyTwentyMinutes();
}

4. Use the Token in Other Requests

Whenever you need to make authenticated requests to the API, use the token from the AuthenticationService.

$response = Http::withHeaders([
    'Authorization' => 'Bearer ' . $authService->getToken(),
])->get('https://server/restapi/v2.0/endpoint');

One potential problem that I can think of here is that there might be a rate limit and requesting a new token every 20 mins might be too much, so it would be worth checking if this is the case in the API docs.

What I could also mention is that you would need to ensure that you handle tokens securely, potentially by storing them in a secure way in your environment, especially if they are long-lived refresh tokens. Also, make sure to handle failures and edge cases (e.g., token expiration, server errors) gracefully within your application.

You can take a look at this post here on how to use encryption:

How to encrypt and decrypt a string in Laravel?

Hope that this helps!

Best,

Bobby

superdev

Aug 17th, 2023 07:15 PM

Hi Brian 👋

Please check my article attached below to solve your problem: https://devdojo.com/superdev/how-to-add-two-factor-authentication-to-your-laravel-application

Report
1
bobbyiliev

Aug 18th, 2023 01:18 AM

Ah nice! Thanks for sharing that @superdev!

brianh

Aug 18th, 2023 05:31 AM

Hi Guys,

Thanks for the feedback.

Just a small clarification. The data I am trying to consume is coming from another system that I do not have any control over.

I want to read data from that system using a API which will only function once I am authenticated using 2FA.

It does indeed have a refresh token available. How would I use this? Sorry for the basic question.

bobbyiliev

Aug 20th, 2023 11:17 PM

Best Answer

Hey 👋

No problem at all! Refresh tokens are commonly used to obtain new access tokens without requiring the user to log in again. Since you mentioned that the server supports refresh tokens, here's how you might use them:

  1. Modify the Authentication Service: First, make sure to save both the access token and the refresh token that you receive after the initial authentication. You might modify your AuthenticationService class like this:
public function authenticate($username, $password, $totp)
{
    $response = Http::post('https://server/restapi/v2.0/auth', [
        // ... your authentication data
    ]);

    if ($response->successful()) {
        $this->token = $response->json()['token'];
        $this->refreshToken = $response->json()['refresh_token']; // Assuming the key is 'refresh_token'
        return $this->token;
    }

    throw new \Exception('Authentication failed');
}

public function refresh()
{
    $response = Http::post('https://server/restapi/v2.0/auth/refresh', [ // Adjust this URL as needed
        'refresh_token' => $this->refreshToken,
    ]);

    if ($response->successful()) {
        $this->token = $response->json()['token'];
    } else {
        // Handle error
    }
}
  1. Schedule the Token Refresh: As before, you can use Laravel's task scheduling to run the refresh method every 20 minutes:
protected function schedule(Schedule $schedule)
{
    $schedule->call(function (AuthenticationService $authService) {
        $authService->refresh();
    })->everyTwentyMinutes();
}
  1. Use the Token Securely: Make sure to store the tokens securely and handle any errors that might occur when refreshing. Since tokens are sensitive, you might want to encrypt them before saving them in your database or caching layer.

    Laravel provides an easy way to encrypt and decrypt values using the encrypt and decrypt functions:

$encryptedToken = encrypt($token);
$decryptedToken = decrypt($encryptedToken);

By using the refresh token in this way, you can maintain an authenticated session without needing the user to re-enter the OTP. You just have to ensure that the refresh token is stored securely and that you have proper error handling in place for any issues that might arise during the token refresh process.

Here is also a good article on refresh tokens that might be helpful:

What Are Refresh Tokens and How to Use Them Securely

Report
1