Laravel 12 - Digital Signatures with Sign Pad.
Laravel 12 - Digital Signatures with Sign Pad.
In this tutorial, we will learn how to add a Digital Signature feature in Laravel 12 using Sign Pad. You’ll see how to capture, save, and display user signatures securely for agreements, forms, and online document verification.
If you're a video person, feel free to skip the post and check out the video instead!
Quick Overview
This guide walks you through integrating a digital signature feature into your Laravel 12 application. You’ll start with a fresh Laravel project or an existing one, install the laravel-sign-pad package, and publish the required configuration and migration files. The User model and routes are updated to handle signatures, and a UserController manages user data and signatures. Blade views are created for submitting user details and signatures, as well as displaying the saved agreement. Finally, you can test the application by submitting the form and viewing the agreement using the user’s ID.
Step # 1 : Set Up New Laravel Project Named Signature.
Before we dive in, you’ll need a fresh Laravel installation. You can either create a brand-new project or use an existing one. For this guide, we’ll start from scratch and name our project signature. If you have the Laravel Installer installed globally, you can run.
laravel new signature
No installer? No problem! Composer works just as well.
composer create-project laravel/laravel --prefer-dist signature
When using Composer, you won’t see the interactive setup prompts. Those prompts appear only when using the Laravel Installer. When using the Laravel Installer, you’ll be guided through a few setup prompts.
- Would you like to install the starter kit? — Choose None.
- After selecting None, you'll be asked about testing framework. — Choose Pest.
- After selecting Pest, you'll be asked to select the database for your application. — Choose MySQL.
- After selecting MySQL, you'll be asked if you want to run the default database migration. — Choose Yes.
- Finally, type yes if prompted, or run npm install and npm run build to install and compile your frontend dependencies.
As a result, you now have a fresh Laravel 12 project named signature, with the testing framework and database set up if you used the Installer, and your frontend assets ready to go.
Step # 2 : Navigate to Your Laravel Project.
Open your terminal (for example, Git Bash, Terminal, or Command Prompt) and navigate to the root folder of your Laravel project by running.
cd c:xampp/htdocs/signature
This command takes you into your project directory so you can start working on your Laravel application.
Step # 3 : Install the SignPad Package.
To add digital signature functionality to your Laravel project, run the following command.
composer require creagia/laravel-sign-pad
This will download and install the Laravel SignPad package, enabling you to capture and store digital signatures directly within your application.
Step # 4 : Publish Config, Migrations and Assets for SignPad.
Run the following command to publish the package configuration, migration, and assets.
php artisan sign-pad:install
During the installation, you'll be prompted to run the migrations, type yes to proceed. After the migration details, you'll be asked if you want to star the repository on GitHub, type yes to star or no to skip. Then, publish the JavaScript assets by running.
php artisan vendor:publish --tag=sign-pad-assets
After completing these steps, the SignPad package is installed with its migrations and assets published, and is ready for further configuration in your Laravel project.
Step # 5 : Add Signature Functionality to Your User Model.
Update the User model to support digital signatures by adding the required traits and implementing the necessary contract.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
// Include signature handling traits and contracts
use Creagia\LaravelSignPad\Concerns\RequiresSignature;
use Creagia\LaravelSignPad\Contracts\CanBeSigned;
// User model implements CanBeSigned for signature capabilities
class User extends Authenticatable implements CanBeSigned
{
/** @use HasFactory<\Database\Factories\UserFactory> */
// Use RequiresSignature for handling digital signatures
use HasFactory, Notifiable, RequiresSignature;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}
This change enables your User model to manage digital signatures, giving each user the ability to sign documents. It integrates signature functionality directly into your Laravel application, making it ready for further configuration and use.
Step # 6 : Define the Routes.
Next, import the UserController class and define the routes inside your web.php file.
use App\Http\Controllers\UserController;
// Display the user creation form
Route::get('/', [UserController::class, 'create']);
// Handle form submission and store the user’s data and signature
Route::post('/confirm', [UserController::class, 'store']);
// Display the user’s agreement details
Route::get('/show/{user}', [UserController::class, 'show']);
These routes handle the main workflow, displaying the form, saving the user’s information and signature, and showing the saved agreement details.
Step # 7 : Create the UserController.
Generate the UserController by running the following Artisan command.
php artisan make:controller UserController
Next, open the newly created UserController.php file and replace its content with the code below. This controller will handle user creation, signature storage, and displaying agreement details.
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Creagia\LaravelSignPad\Signature;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class UserController extends Controller
{
/**
* Display the signature form view.
*/
public function create()
{
return view('sign');
}
/**
* Handle form submission, validate input,
* store user information and signature.
*/
public function store(Request $request)
{
// Validate user input
$validatedData = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:8',
'sign' => 'required',
]);
// Create a new user record
$user = User::create($validatedData);
// Decode and store the signature image
$signatureData = str_replace('data:image/png;base64,', '', $validatedData['sign']);
$signatureData = base64_decode($signatureData);
// Generate a unique filename and save the image to storage
$imageName = 'signatures/' . Str::uuid() . '.png';
Storage::disk('public')->put($imageName, $signatureData);
// Save signature details in the database
$signature = new Signature();
$signature->model_type = User::class;
$signature->model_id = $user->id;
$signature->uuid = Str::uuid();
$signature->filename = $imageName;
$signature->document_filename = null;
$signature->certified = false;
$signature->from_ips = json_encode([request()->ip()]);
$signature->save();
// Redirect back with a success message
return redirect()->back()->with('success', 'Employment Agreement submitted successfully!');
}
/**
* Display the stored user and signature details.
*/
public function show(User $user)
{
$user->load('signature');
return view('show', compact('user'));
}
}
This controller defines three primary methods, create(), which displays the signature form, store(), which validates input, saves user details, and stores the signature image, and show(), which retrieves and displays the user’s agreement details.
Step # 8 : Create a Storage Link.
Run the following Artisan command to create a symbolic link between the public and storage directories.
php artisan storage:link
This command ensures that any files stored in the storage folder are accessible through the public directory.
Step # 9 : Create the Views.
Now, let’s create the views for the application. Start by creating a file named sign.blade.php inside the resources/views directory. This view contains a form that allows users to enter their details, such as name, email, password, and sign the employment agreement.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Code Shotcut - Employment Agreement</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* Submit & Clear button styling (uniform) */
.sign-pad-button-submit,
.sign-pad-button-clear {
margin-top: 10px;
padding: 0.75rem 1.25rem; /* same for both */
font-weight: bold;
border-radius: 0.5rem;
transition: background-color 0.3s ease;
font-size: 1rem;
color: white;
}
.sign-pad-button-submit {
background-color: #3b82f6; /* blue */
}
.sign-pad-button-submit:hover {
background-color: #2563eb;
}
.sign-pad-button-clear {
background-color: #ef4444; /* red */
}
.sign-pad-button-clear:hover {
background-color: #dc2626;
}
</style>
</head>
<body class="bg-gray-900 flex items-start justify-center py-10 text-gray-100">
<!-- Form Container -->
<form action="/confirm" method="POST" class="bg-white p-8 rounded-2xl shadow-2xl max-w-xl w-full">
@csrf
<!-- Heading -->
<h3 class="text-2xl font-bold text-center mb-1 text-gray-900">Code Shotcut - Employment Agreement</h3>
<!-- Description -->
<p class="text-center text-gray-600 mb-5">
Welcome to Code Shotcut! Please provide your details below and sign to confirm your acceptance of the employment terms.
</p>
<!-- Success Message -->
@if (session('success'))
<div class="bg-green-100 text-green-700 p-4 rounded mb-3">
{{ session('success') }}
</div>
@endif
<!-- Validation Error Messages -->
@if ($errors->any())
<div class="bg-red-100 text-red-700 p-4 rounded mb-3">
<ul class="list-disc list-inside">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<!-- Full Name Input -->
<div class="mb-4">
<label for="name" class="block text-lg font-semibold mb-1 text-gray-800">Full Name</label>
<input type="text" id="name" name="name"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 text-gray-900"
placeholder="Enter your full name" required />
</div>
<!-- Email Input -->
<div class="mb-4">
<label for="email" class="block text-lg font-semibold mb-1 text-gray-800">Email Address</label>
<input type="email" id="email" name="email"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 text-gray-900"
placeholder="Enter your email" required />
</div>
<!-- Password Input -->
<div class="mb-4">
<label for="password" class="block text-lg font-semibold mb-1 text-gray-800">Password</label>
<input type="password" id="password" name="password"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 text-gray-900"
placeholder="Create a password" required />
</div>
<!-- Signature Pad -->
<div class="mb-5">
<label class="block text-lg font-semibold mb-1 text-gray-800">Digital Signature</label>
<p class="text-gray-500 mb-1 text-sm">
Sign below using your mouse or touch device to complete your agreement with Code Shotcut.
</p>
<x-creagia-signature-pad name='sign' />
</div>
</form>
<!-- Sign-pad JS -->
<script src="{{ asset('vendor/sign-pad/sign-pad.min.js') }}"></script>
</body>
</html>
Next, create another view named show.blade.php in the same resources/views directory. This file will display the user’s agreement details, including their name, email, and signature image (if available).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Code Shotcut - User Agreement</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-900 flex items-center justify-center min-h-screen text-gray-100">
<!-- User Agreement Container -->
<div class="bg-white p-8 rounded-2xl shadow-2xl max-w-md w-full text-gray-900">
<!-- Heading -->
<h3 class="text-2xl font-bold text-center mb-2">Code Shotcut - User Agreement</h3>
<!-- Description -->
<p class="text-center text-gray-600 mb-5">
Below are the details you submitted along with your digital signature.
</p>
<!-- User Details -->
<div class="mb-4">
<p class="mb-2"><strong>Name:</strong> {{ $user->name }}</p>
<p><strong>Email:</strong> {{ $user->email }}</p>
</div>
<!-- Signature Section -->
<div class="mb-4">
<h4 class="text-lg font-semibold mb-1 text-gray-800">Digital Signature</h4>
@if ($user->signature)
<img src="{{ asset('storage/' . $user->signature->filename) }}" alt="User Signature" class="w-full h-auto rounded-lg border border-gray-300">
@else
<p class="text-gray-500">No signature available.</p>
@endif
</div>
</div>
</body>
</html>
These Blade templates provide the front-end for submitting user details and signatures, and for viewing the saved agreement information.
Step # 10 : Testing the Signature Pad.
Start the Laravel development server by running.
php artisan serve
Then, open your web browser and go to: http://127.0.0.1:8000.You should see the employment agreement form. Fill in all the required details and submit the form to store the user information along with their signature.
To view a submitted agreement, navigate to: http://127.0.0.1:8000/show/{id}. Replace {id} with the actual user ID to see the user’s details and their saved signature.
Conclusion
By following this guide, you’ve successfully added a digital signature feature to your Laravel application. Users can now enter their details and submit a secure digital signature, which is stored safely within the system. With the laravel-sign-pad package handling the signature functionality, your application provides a reliable and efficient way to collect and display user agreements. You can also customize this setup further to match your specific requirements.
For more information, refer to the laravel-sign-pad documentation.
Share this with friends!
To engage in commentary, kindly proceed by logging in or registering
Subscribe to Our Newsletter
Stay ahead of the curve! Join our newsletter to see what everyone’s talking about.
0 Comments