Skip to content

Utilizing JWT & WebAuthn together in PHP REST API

License

Notifications You must be signed in to change notification settings

wnelson03/jwt-webauthn-php

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JWT & WebAuthn demo

Utilizing JWT & WebAuthn together in a backend API.

Made this for the digital E-commerce service @Sellix in hopes to get an internship with them.

Edit: I got the internship though my university only accepts large corporate jobs. Sellix is still an awesome company who actually cares about their users, they're always adding new features. Here's my referral link for 30% off discount https://ref.sellix.io/s/register/316675

Didn't use Redis for this, since I wanted it to work out-of-the-box for people lacking the PHPRedis extension.

On a live website, Redis or Memcached should be employed to cache data from database, and to blacklist JWT tokens on logout/password reset.

Showcase

jwt-webauthn-php.mp4

Requirements

PHP >= 8.0.0

MySQL Server with mysqlnd

Setup

Import schema.sql into MySQL or MariaDB and you can run the demo.

For a live website, make sure to change credentials first.

Privacy

Emails are hashed with SHA1 so that the operator can't see plain-text emails.

No model name or serial numbers are collected for WebAuthn. The operator can't tell if you're using YubiKey or SoloKey, or any other WebAuthn-compatible device

Database sample

Accounts table:

id email password securityKey
21 26bead3658ccd9d4598bdca509f9b42cf6b8a3f5 $2y$10$s... 1

securitykeys table:

id account credentialId credentialPublicKey
3 21 WJTV6t9GmYgGVS8h2OHkZkPGeqUECCe3xOc5sds6WCpMSi8r+9oWZsIdQiEp/nFUkGnv2PqPaZ9ezs6wnGDfkQ== -----BEGIN PUBLIC KEY-----MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoTQh+4LXNHgMEtAgLrrkJBdFXPoZtciHcs+dJbKA7O/GYdIyfI92Pa8RMoHTCE5EuMp2XkqdxUgTmiq+Ao6AMw==-----END PUBLIC KEY-----

JWT sample

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MjEsImF1dGgiOnRydWUsIm1mYSI6bnVsbCwiZW1haWwiOiIyNmJlYWQzNjU4Y2NkOWQ0NTk4YmRjYTUwOWY5YjQyY2Y2YjhhM2Y1In0.065m3mWiufxgUDSj2VUAGS3x4bwW6KLcFBs1shJCrlA

Decoded

{"typ":"JWT","alg":"HS256"}{"id":21,"auth":true,"mfa":null,"email":"26bead3658ccd9d4598bdca509f9b42cf6b8a3f5"}<signatureHere>

Credentials

In a live website, these credentials should be changed and stored in a seperate configuration file such as credentials.php, and then you add credentials.php to the .gitignore and make a credentials.example.php for public use.

Another way would be setting the credentials via FastCGI Params in nginx, to create further seperation between the credentials and the source code.

JWT Secret

$session = Firebase\JWT\JWT::decode($_COOKIE[$this->sessionName], new Firebase\JWT\Key('yWvati2Z94ZV6XFaSwC7gqdsabtTYHqMnzWB7o58AvCXHkheS8ANfHLKTTwXE9cXHg7GH2bSb9q95Lo2He9XDWtqDBwJzvKFbX8ymeLPkhFQkJxF8GDbmpRUfeXctiLi', 'HS256'));

$encoded = Firebase\JWT\JWT::encode($payload, 'yWvati2Z94ZV6XFaSwC7gqdsabtTYHqMnzWB7o58AvCXHkheS8ANfHLKTTwXE9cXHg7GH2bSb9q95Lo2He9XDWtqDBwJzvKFbX8ymeLPkhFQkJxF8GDbmpRUfeXctiLi', 'HS256');

MySQL Server

$db = new Database("localhost", "root", "", "jwt-webauthn-php");

$db = new Database("localhost", "root", "", "jwt-webauthn-php");

$db = new Database("localhost", "root", "", "jwt-webauthn-php");