Affinidi Login with PHP

In this guide, learn how to enable passwordless login in your application using Laravel Framework and Socialite.

The Affinidi Login can be integrated with any application that supports OIDC flow.

In this lab, we will use the Laravel framework with Socialite from the available sample applications to take you through the step-by-step guide for creating a Login Configuration and setting up the application to implement passwordless authentication for end-users.

Before you begin
  1. Set up Affinidi Vault account. Follow the guide below if you haven’t set it up yet.
Set up Affinidi Vault

Set up an Affinidi Vault account using the Web Vault or install the Mobile Vault (for Android).

The same setup steps for Mobile Vault.

  1. Click on Get started if you are creating a new account, or click on Restore from Backup if you have an existing backup of your Affinidi Vault. Provide the Passphrase to secure your Affinidi Vault.

You have the option to enable Biometrics to unlock your Affinidi Vault easily instead of using Passphrase.

Affinidi Vault Setup
  1. Enter your email address to register with the Affinidi Vault. An OTP will be sent to this email for verification.
Affinidi Vault Passphrase
  1. Enter the OTP sent to the email you have provided for verification to complete the setup.
Affinidi Vault Email Verification

After successfully providing the OTP, you are redirected to the Affinidi Vault dashboard.

  1. Get the Redirect URI of your application for OIDC. This is the URI configured on your Login Configuration to receive the idToken after successful authorisation.

  2. Optionally, install the Affinidi CLI. Follow the guide below if it hasn’t been installed.

Set up Affinidi CLI
  1. Download and install NodeJS on your machine if you haven’t set it up yet.
  1. Install Affinidi CLI using Node Package Manager (npm).
npm install -g @affinidi/cli
  1. Verify that the installation is successful.
affinidi --version
  1. Setup Composer on your machine to install PHP dependencies in Laravel.

Download Application

You can clone this sample application from our Github and start exploring how to integrate Affinidi Login to provide a passwordless login experience for your end-users.

Create Login Configuration

To create a Login Configuration, you can either use Affinidi CLI or  Affinidi Portal.

Expand the section below for your preferred method:

Laravel Sample App Settings:

Name: Laravel Socialite

Redirect URIs: http://localhost:8010/login/affinidi/callback

Using Affinidi CLI
  1. Log in to Affinidi CLI by running:
affinidi start
  1. Once you have successfully logged in, create the Login Configuration by running:
affinidi login create-config \
--name='Laravel Socialite' \
--redirect-uris='http://localhost:8010/login/affinidi/callback'
  • --name is what you want your login configuration to be called.
  • --redirect-uris is the URL on your application where the user gets redirected after the successful authentication.

Learn more on how to manage your Login Configurations using Affinidi CLI.

Using Affinidi Portal
Create new Login Configuratioin
  1. Go to  Affinidi Login under the Services section.

  2. Click on the Create Login Configuration and provide the required details.

  • Name is the string that describes your login configuration.
  • Redirect URIs is the URL on your application where the user gets redirected after the successful authentication.
  1. Click on create and confirm if all the details are correct.
Login Configuratation new client
  1. After confirming the details, another popup shows the Client ID and Client Secret for your Login Configuration. Copy the generated Client Credentials and use them to integrate with Affinidi Login.

  2. After copying the Client ID and Client Secret and closing the popup, you are redirected back to the Affinidi Login page.

Login Configuration uses the default Presentation Definition (presentationDefinition) and ID Token Mapping (idTokenMapping) that is used to request the user’s email address during the authentication flow.

Set up the Sample Application

After creating the Login Configuration required to set up the sample application. Let’s start setting up the Laravel application by configuring the following settings:

Configure Env Variables

Create the .env file using the following command:

cp .env.example .env

Set the environment variables based on the auth credentials received from the Login Configuration created earlier:

{
  "auth": {
    "clientId": "<AUTH.CLIENT_ID>",
    "clientSecret": "<AUTH.CLIENT_SECRET>",
    "issuer": "https://<PROJECT_ID>.apse1.login.affinidi.io"
  }
}

Set the following fields in the .env file

PROVIDER_CLIENT_ID="<AUTH.CLIENT_ID>"
PROVIDER_CLIENT_SECRET="<AUTH.CLIENT_SECRET>"
PROVIDER_ISSUER="<AUTH.CLIENT_ISSUER>"

Install Dependencies

Go to the Laravel directory and install the Laravel dependencies with Composer using the following command:

Setup Composer on your machine to install PHP dependencies in Laravel.

composer install

Running the Application

After configuring the .env file and installing the required Laravel dependencies, run the application using the following command:

php artisan serve

After successfully running the command, go to http://localhost:8010 to access the page with the Affinidi Login button.

Key Changes to Sample Application

Controllers

Laravel Controller class allow developers to define and group related routes to handle incoming requests. In our sample application, we have defined the App\Http\LoginRegisterController class to handle the request:


namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;

class LoginRegisterController extends Controller
{

    public function login()
    {
        return view('login');
    }

    public function home()
    {
        if (session("user")) {
            return view('dashboard');
        }

        return redirect()->route('login')
            ->withErrors([
                'email' => 'Please login to access the home.',
            ]);
    }

    public function logout(Request $request)
    {
        Auth::logout();
        $request->session()->invalidate();
        $request->session()->regenerateToken();
        return redirect()->route('login')
            ->withSuccess('You have logged out successfully!');
        ;
    }

    public function affinidiLogin(Request $request)
    {
        return Socialite::driver('affinidi')->redirect();
    }

    public function affinidiCallback(Request $request)
    {
        try {
            $user = Socialite::driver('affinidi')->user();

            session(['user' => $user]);

            return redirect()->intended('home');
        } catch (\Exception $e) {
            return redirect()->route('login')
                ->withError($e->getMessage());
        }
    }
}

In the LoginRegisterController class, we have defined 2 key endpoints to integrate Affinidi Login.

  • affinidiLogin that triggers a redirect using the Socialite OAuth provider to initiate the Affinidi Login authentication flow.

  • affinidiCallback to receive the callback response from Affinidi Login after successful user authentication. We call the Socialite OAuth provider to parse the ID Token that contains the user’s information. We received information based on the defined Presentation Definition and ID Token Mapping in Login Configuration.

AffinidiSocialite Provider

Using the composer.json, we have imported affinidi/laravel-socialite-affinidi to register Affinidi as the Auth Provider using Socialite in Laravel.

After importing the required library, we have defined Affinidi in the App\Providers\AppServiceProvider to bootstrap the AffinidiSocialite driver to handle the Affinidi Login flow.

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Laravel\Socialite\Contracts\Factory;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        $socialite = $this->app->make(Factory::class);

        //Setup affinidi driver
        \Affinidi\SocialiteProvider\AffinidiSocialite::extend($socialite);
    }
}

Summary

sequenceDiagram
    actor User
    participant Laravel
    participant Affinidi Login
    participant Affinidi Vault
    participant Affinidi Verifier

    User->>Laravel: My Login
    Laravel->>Affinidi Login: Authenticate user
    Note over Laravel, Affinidi Login:  login_challenge
    Affinidi Login->>Affinidi Vault: Verify user identity
    Note over Affinidi Login, Affinidi Vault:  presentationDefinition
    Affinidi Vault->>User: Request user confirmation to share Email VC
    User->>Affinidi Vault: User confirmed consent to share Email VC
    Affinidi Vault->>Affinidi Vault: Generate VP Token from VC
    Affinidi Vault->>Affinidi Login: Send Email VP Token
    Affinidi Login->>Affinidi Verifier: Validate VP Token
    Note over Affinidi Login, Affinidi Verifier:  vp_token, presentation_submission, presentation_definition
    Affinidi Login->>Affinidi Login: Generate idToken
    Affinidi Login->>Laravel: Send generated idToken from VP
    Laravel->>User: Provide access to the user

Using the Laravel framework as the sample application, we have configured it to integrate with Affinidi Login as the Auth provider and parse the idToken sent by the Affinidi Login to confirm the user’s successful authentication using the Affinidi Vault.