1Password Passage SDK for PHP Developers.
Read the article »
Report Bug
·
Request Feature
Table of Contents
Introducing Passage SDK for PHP:
- Seamless integration with 1Password's Passage API
- Secure storage and retrieval of secrets
- Magic link authentication implementation
- Robust error handling
- Automatic conversion to native PHP
DateTime
objects - Middleware support for easy integration
- Powerful SDK features for enhanced security in PHP projects
Start by creating a laravel/laravel
project using PHP composer:
- composer
laravel new my-php-project
- Create a Passage account
- Create a new Passage application
- Retrieve your application's
<APP_ID>
and<API_KEY>
- Add
<APP_ID>
and<API_KEY>
to your local.env
file:APP_ID=your_app_id API_KEY=your_api_key
- Install package from Packagist
composer require eludadev/passage
- Import the
Passage
classuse Eludadev\Passage\Passage;
- Create an instance of the
Passage
class.
Set<AUTH_STRATEGY>
to either'COOKIES'
(default) or'HEADER'
.$passage = new Passage(env('APP_ID'), env('API_KEY'), '<AUTH_STRATEGY>' /* optional */);
Authenticate requests and manage Passage users with Node.js.
Warning To use the Passage PHP SDK, you'll need your Passage App ID. You can create a new Passage App in the console.
Note Assuming you followed the above prerequisites to create a new
laravel/laravel
project, you can quickly get started using this SDK in your API routes by opening theroutes/web.php
file and adding the following code:
use Illuminate\Http\Request;
use Eludadev\Passage\Passage;
use Illuminate\Support\Facades\Route;
Route::get('/passage', function (Request $request) {
$passage = new Passage(env('APP_ID'), env('API_KEY'));
return $passage->createMagicLink("example@domain.com", "/redirect");
});
Passage makes it easy to associate an HTTP request with an authenticated user. The following code can be used to validate that a request was made by an authenticated user.
use Illuminate\Http\Request;
use Eludadev\Passage\Passage;
use Illuminate\Support\Facades\Route;
// Authentication using Passage class instance
Route::get('authenticatedRoute', function (Request $request) {
$passage = new Passage(env('APP_ID'), env('API_KEY'));
try {
// Authenticate request using Passage
$userID = $passage->authenticateRequest($request);
if ($userID) {
// User is authenticated
$userData = $passage->user->get($userID);
return;
}
} catch (\Exception $e) {
// Authentication failed
return "Authentication failed!";
}
});
By default, Passage looks for the user JWT from a cookie that is set by the Passage Element (psg_auth_token
). If your application uses Authorization headers instead, you can pass the following option to the Passage PHP SDK.
$passage = new Passage(env('APP_ID'), env('API_KEY'), 'HEADER');
If you used the laravel/laravel
project, Passage provides a middleware that can be used directly. This middleware will authenticate a request and return a 401 Unauthorized if the token is invalid. If it succeeds, the Passage User ID will be available in the response. The following code shows how the Passage middleware can be used in a PHP application.
use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;
use Eludadev\Passage\Passage;
use Eludadev\Passage\Middleware\PassageAuthMiddleware;
// Example of passage middleware
Route::get('authenticatedRoute', function (Request $request) {
$passage = new Passage(env('APP_ID'), env('API_KEY'));
$userID = $request->userID;
})->middleware(PassageAuthMiddleware::class);
If you are not using eludadev/passage
in a request context, or your application is passing the JWT in a custom way, you can pass the JWT directly to the validAuthToken
method to perform validation.
$userID = $passage->validAuthToken($token);
if ($userID) {
//authenticated
}
// otherwise, unauthorized
The Passage SDK provides a way to retrieve information about an app.
use Eludadev\Passage\Passage;
$passage = new Passage(env('APP_ID'), env('API_KEY'));
$appInfo = $passage->getApp();
In addition to authenticating requests, the Passage PHP SDK also provides a way to securely manage your users. These functions require authentication using a Passage API key. API keys can be managed in the Passage Console.
The functionality currently available on a user is:
- Get a user's information (including any defined user metadata)
- Activate or deactivate a user (a deactivated user will not be able to log in)
- Update a user's information (email address or phone number)
- Delete a user
- Create a user
Warning Passage API Keys are sensitive! You should store them securely along with your other application secrets.
Get
use Illuminate\Http\Request;
use Eludadev\Passage\Passage;
use Eludadev\Passage\Middleware\PassageAuthMiddleware;
Route::get('authenticatedRoute', function (Request $request) {
$passage = new Passage(env('APP_ID'), env('API_KEY'));
$userID = $request->userID;
$passageUser = $passage->user->get($userID);
return $passageUser->email;
})->middleware(PassageAuthMiddleware::class);
Activate/Deactivate
use Illuminate\Http\Request;
use Eludadev\Passage\Passage;
use Eludadev\Passage\Middleware\PassageAuthMiddleware;
Route::get('authenticatedRoute', function (Request $request) {
$passage = new Passage(env('APP_ID'), env('API_KEY'));
$userID = $request->userID;
$deactivatedUser = $passage->user->deactivate($userID);
$deactivatedUser->active; // false
$activatedUser = $passage->user->activate($userID);
$activatedUser->active; // true
})->middleware(PassageAuthMiddleware::class);
Update
use Illuminate\Http\Request;
use Eludadev\Passage\Passage;
use Eludadev\Passage\Middleware\PassageAuthMiddleware;
Route::get('authenticatedRoute', function (Request $request) {
$passage = new Passage(env('APP_ID'), env('API_KEY'));
$userID = $request->userID;
$passageUser = $passage->user->update($userID, [
'email' => 'testEmail@domain.com',
'phone' => '+15005550006'
]);
$passageUser->email; // testEmail@domain.com
$passageUser->phone; // +15005550006
})->middleware(PassageAuthMiddleware::class);
Delete
use Illuminate\Http\Request;
use Eludadev\Passage\Passage;
use Eludadev\Passage\Middleware\PassageAuthMiddleware;
Route::get('authenticatedRoute', function (Request $request) {
$passage = new Passage(env('APP_ID'), env('API_KEY'));
$userID = $request->userID;
$deletedUser = $passage->user->delete($userID);
$deletedUser; // true
})->middleware(PassageAuthMiddleware::class);
Create
use Eludadev\Passage\Passage;
$passage = new Passage(env('APP_ID'), env('API_KEY'));
$newUser1 = $passage->user->create('testEmail@domain.com');
$newUser1->email; // testEmail@domain.com
$newUser2 = $passage->user->create(phone:'+15005550006');
$newUser2->phone; // +15005550006
Field | Type |
---|---|
id | string |
string | |
phone | string |
active | boolean |
email_verified | boolean |
created_at | DateTime |
last_login_at | DateTime |
webauthn | boolean |
user_metadata | array |
webauthn_devices | array of strings (e.g. "Mac OS X") |
recent_events | array of strings |
The functionality currently available is:
- List all devices for a user
- Revoke a particular device from a user
List Devices
use Illuminate\Http\Request;
use Eludadev\Passage\Passage;
use Eludadev\Passage\Middleware\PassageAuthMiddleware;
Route::get('authenticatedRoute', function (Request $request) {
$passage = new Passage(env('APP_ID'), env('API_KEY'));
$userID = $request->userID;
$devices = $passage->user->listDevices($userID);
return $devices;
})->middleware(PassageAuthMiddleware::class);
Revoke Device
use Illuminate\Http\Request;
use Eludadev\Passage\Passage;
use Eludadev\Passage\Middleware\PassageAuthMiddleware;
Route::get('authenticatedRoute', function (Request $request) {
$passage = new Passage(env('APP_ID'), env('API_KEY'));
$userID = $request->userID;
$success = $passage->user->revokeDevice($userID, '<DEVICE_ID>');
return $success; // true
})->middleware(PassageAuthMiddleware::class);
The PHP SDK can be used to generate custom magic links (called "smart links") for users, that can be embedded into any content medium. To learn more, see our full guide on Smart Links.
use Eludadev\Passage\Passage;
$passage = new Passage(env('APP_ID'), env('API_KEY'));
$magicLink = $passage->createMagicLink('newEmail@domain.com', '/custom-path/1234');
// use Magic Link URL
$magicLink->url;
We built an example full-stack application on React and a PHP backend.
Get started by opening the following directory: cd ./examples
Warning Make sure you have PHP and Composer installed on your local machine before continuing with these steps.
Create a new Passage project.
Make sure to input http://localhost:3000
for the domain, and /dashboard
for the redirect URL.
Head over to your project settings.
Input http://localhost:3000
for the domain, and /dashboard
for the redirect URL, and /
for the login URL.
- Go to the backend directory:
cd ./backend
- Install the dependencies:
composer install
- Copy the environment variables file:
cp .env.example .env
- Replace your Passage credentials in
.env
:PASSAGE_APP_ID= PASSAGE_API_KEY=
- Run the server:
php artisan serve
- Go to the frontend directory:
cd ./frontend
- Install the dependencies:
yarn
- Copy the environment variables file:
cp EXAMPLE.env .env
- Replace your Passage credentials in
.env
:REACT_APP_PASSAGE_APP_ID=
- Run the server:
yarn start
Here's the code powering the PHP backend:
// routes/api.php
<?php
use Eludadev\Passage\Errors\PassageError;
use Eludadev\Passage\Passage;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
// This route handles the authentication process for the '/auth' endpoint
Route::post('/auth', function (Request $request) {
try {
// Create a new instance of the Passage class using the Passage API credentials from the environment variables
$passage = new Passage(env('PASSAGE_APP_ID'), env('PASSAGE_API_KEY'), 'HEADER');
// Authenticate the request using the Passage API
$userId = $passage->authenticateRequest($request);
if ($userId) {
// If authentication is successful, retrieve user data using the Passage API
$userData = $passage->user->get($userId);
// Determine the identifier based on the user data (email or phone)
$identifier = $userData['email'] ? $userData['email'] : $userData['phone'];
// Return the authentication status and identifier
return [
'authStatus' => 'success',
'identifier' => $identifier
];
}
} catch (PassageError $e) {
// Catch any errors that occur during the authentication process and echo the error message
echo $e->getMessage();
// Return the authentication failure status
return [
'authStatus' => 'failure'
];
}
});
For this particular example, we chose to build the server on the Laravel framework, but the Passage PHP SDK can work on any PHP framework.
The frontend calls the localhost:8000/api/auth
URL, which extracts the authentication header, decodes the JWK token, and retrieves the user ID. It then makes calls to the Passage API to retrieve more user information such as email and phone number.
All of this is done behind the scenes by the PHP SDK, so you don't have to worry about the intricate details.
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
Distributed under the MIT License. See LICENSE
for more information.
Younes Laaroussi - Telegram - hello@eluda.dev
Project Link: https://github.com/eludadev/Passage
Many thanks to 1Password and Hashnode for hosting this amazing hackathon! It was a lot of fun and a fantastic learning experience for me and all the other participants, and hopefully it can happen again! ❤️