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.
jwt-webauthn-php.mp4
PHP >= 8.0.0
MySQL Server with mysqlnd
Import schema.sql
into MySQL or MariaDB and you can run the demo.
For a live website, make sure to change credentials first.
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
Accounts table:
id | 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----- |
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MjEsImF1dGgiOnRydWUsIm1mYSI6bnVsbCwiZW1haWwiOiIyNmJlYWQzNjU4Y2NkOWQ0NTk4YmRjYTUwOWY5YjQyY2Y2YjhhM2Y1In0.065m3mWiufxgUDSj2VUAGS3x4bwW6KLcFBs1shJCrlA
Decoded
{"typ":"JWT","alg":"HS256"}{"id":21,"auth":true,"mfa":null,"email":"26bead3658ccd9d4598bdca509f9b42cf6b8a3f5"}<signatureHere>
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
Line 15 in ebffedc
Line 29 in ebffedc
MySQL Server
Line 53 in ebffedc
Line 79 in ebffedc
jwt-webauthn-php/api/routing.php
Line 81 in ebffedc