Skip to content

Instantly share code, notes, and snippets.

@darkterminal
Last active August 20, 2024 18:46
Show Gist options
  • Save darkterminal/c272bf2a572bc5d7378f31cf4aea5f19 to your computer and use it in GitHub Desktop.
Save darkterminal/c272bf2a572bc5d7378f31cf4aea5f19 to your computer and use it in GitHub Desktop.
Turso Database Token Generator for PHP

Explanation and Usage

This code will generate token for Local Development process with Turso. When you use turso-cli or sqld you need to generate database token to connect with your database remotely.

  • full_access_token - Used to connect with database with full access mode
  • read_only_token - Use to connect with database with read access only mode
  • public_key_pem and public_key_base64 - Use as decoding key in our server

Referring to Turso Docs - Local Development

It’s recommended to use environment variables for both url and authToken for a seamless developer experience.

Save the public_key_pem and public_key_base64 in a file:

Filename: jwt_key.pem for public_key_pem

-----BEGIN PUBLIC KEY-----
r9sVX1erm38EStmIHiKh5IvPqtrlUyTRn54s8xkMkdg=
-----END PUBLIC KEY-----

Filename: jwt_key.base64 for public_key_base64

r9sVX1erm38EStmIHiKh5IvPqtrlUyTRn54s8xkMkdg

Environment Variables

sqld usage:

SQLD_AUTH_JWT_KEY_FILE=/path/to/jwt_key.pem

or

sqld -d $(pwd)/local.db --http-listen-addr=127.0.0.1:8080 --enable-http-console --auth-jwt-key-file=./jwt_key.pem

turso dev - cli

turso dev --db-file local.db --auth-jwt-key-file /path/to/jwt_key.pem

Application usage

TURSO_DATABASE_URL=127.0.0.0:8080
TURSO_AUTH_TOKEN=your-full-access-or-read-only-token-here
<?php
// JWT Builder is required:
// Install: composer require lcobucci/jwt paragonie/sodium_compat
// Then copy and paste the code below
// run: php turso-token-generator.php
$requiredExtensions = ['openssl', 'sodium'];
foreach ($requiredExtensions as $ext) {
if (!extension_loaded($ext)) {
die("Error: PHP extension '$ext' is not installed or enabled." . PHP_EOL);
}
}
if (!shell_exec('which openssl')) {
die("Error: OpenSSL command-line tool is not installed or not in your PATH." . PHP_EOL);
}
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
die("Error: Composer autoload file not found. Did you run 'composer install'?" . PHP_EOL);
}
use Lcobucci\JWT\JwtFacade;
use Lcobucci\JWT\Signer\Eddsa;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Token\Builder;
require __DIR__ . '/vendor/autoload.php';
$requiredClasses = [
'Lcobucci\JWT\JwtFacade',
'Lcobucci\JWT\Signer\Eddsa',
'Lcobucci\JWT\Signer\Key\InMemory',
'Lcobucci\JWT\Token\Builder'
];
foreach ($requiredClasses as $class) {
if (!class_exists($class)) {
die("Error: Required class '$class' is not available. Did you run 'composer install'?" . PHP_EOL);
}
}
// Set your expires time in days
$tokenExpiration = 30;
$accessKeysDir = getcwd() . '/access_keys';
if(!is_dir($accessKeysDir)) {
mkdir($accessKeysDir);
}
// Generate privateKey and publicKey
shell_exec("openssl genpkey -algorithm ed25519 -out {$accessKeysDir}/jwt_private.pem");
shell_exec("openssl pkey -in {$accessKeysDir}/jwt_private.pem -outform DER | tail -c 32 > {$accessKeysDir}/jwt_private.binary");
shell_exec("openssl pkey -in {$accessKeysDir}/jwt_private.pem -pubout -out {$accessKeysDir}/jwt_public.pem");
$privateKey = sodium_crypto_sign_secretkey(
sodium_crypto_sign_seed_keypair(
file_get_contents("{$accessKeysDir}/jwt_private.binary")
)
);
unlink("{$accessKeysDir}/jwt_private.binary");
$publicKeyPem = trim(file_get_contents("{$accessKeysDir}/jwt_public.pem"));
$pubKeyBase64 = str_replace(["-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----", "\n", "\r"], '', $publicKeyPem);
$key = InMemory::base64Encoded(
base64_encode($privateKey)
);
// Generate JWT tokens
$now = new DateTimeImmutable();
$fullAccessToken = (new JwtFacade())->issue(
new Eddsa(),
$key,
static fn(
Builder $builder,
DateTimeImmutable $issuedAt
): Builder => $builder
->expiresAt($issuedAt->modify("+$tokenExpiration days"))
);
$readOnlyToken = (new JwtFacade())->issue(
new Eddsa(),
$key,
static fn(
Builder $builder,
DateTimeImmutable $issuedAt
): Builder => $builder
->withClaim('a', 'ro')
->expiresAt($issuedAt->modify("+$tokenExpiration days"))
);
// Prepare response data
$data = [
'full_access_token' => $fullAccessToken->toString(),
'read_only_token' => $readOnlyToken->toString(),
'public_key_pem' => $publicKeyPem,
'public_key_base64' => $pubKeyBase64,
];
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . PHP_EOL;
@darkterminal
Copy link
Author

How great is this! 🥂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment