PHP code example of sandermuller / socialite-solana

1. Go to this page and download the library: Download sandermuller/socialite-solana library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

sandermuller / socialite-solana example snippets


use Illuminate\Support\Facades\Event;
use SanderMuller\SocialiteSolana\SocialiteSolanaExtendSocialite;
use SocialiteProviders\Manager\SocialiteWasCalled;

public function boot(): void
{
    Event::listen(
        SocialiteWasCalled::class,
        [SocialiteSolanaExtendSocialite::class, 'handle'],
    );
}

'solana' => [
    // Required by socialiteproviders/manager but unused by this driver.
    'client_id' => env('SOLANA_CLIENT_ID', 'unused'),
    'client_secret' => env('SOLANA_CLIENT_SECRET', 'unused'),
    'redirect' => env('SOLANA_REDIRECT_URI', '/auth/solana/callback'),

    // Domain shown in the SIWS message. Defaults to APP_URL host.
    'domain' => env('SOLANA_SIWS_DOMAIN'),

    // Canonical URI of the resource being signed in to. Defaults to APP_URL.
    'uri' => env('SOLANA_SIWS_URI'),

    // Human-readable statement (optional).
    'statement' => env('SOLANA_SIWS_STATEMENT', 'Sign in to authenticate.'),

    // Solana cluster: mainnet | devnet | testnet | localnet.
    'chain' => env('SOLANA_SIWS_CHAIN', 'mainnet'),

    // Challenge lifetime in seconds (minimum 60). Default 180 matches typical
    // SIWS reference implementations.
    'ttl' => (int) env('SOLANA_SIWS_TTL', 180),

    // Optional CAIP-122 resource URIs (list of strings).
    'resources' => [],

    // Where the issued challenge lives between buildChallengeFor() and
    // verifyCredentials(). Values: 'session' (default), 'cache', or an FQCN
    // implementing SanderMuller\SocialiteSolana\Contracts\ChallengeStore.
    'store' => env('SOLANA_CHALLENGE_STORE', 'session'),
],

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Str;
use Laravel\Socialite\Facades\Socialite;
use SanderMuller\SocialiteSolana\Exceptions\SolanaAuthException;

Route::post('/auth/solana/challenge', function () {
    return Socialite::driver('solana')->challenge();
})->middleware('web');

Route::post('/auth/solana/callback', function () {
    try {
        $solanaUser = Socialite::driver('solana')->user();
    } catch (SolanaAuthException $e) {
        return response()->json(['error' => $e->getMessage()], 422);
    }

    $user = \App\Models\User::firstOrCreate(
        ['solana_public_key' => $solanaUser->getId()],
        ['password' => Hash::make(Str::random(32))],
    );

    Auth::login($user, remember: true);

    return response()->json(['redirect' => '/home']);
})->middleware('web');

use Laravel\Socialite\Facades\Socialite;
use Livewire\Component;
use SanderMuller\SocialiteSolana\Exceptions\SolanaAuthException;

class SolanaLogin extends Component
{
    public string $walletAddress = '';

    /**
     * Issue a SIWS challenge. The JS layer should `$wire.set('walletAddress', pubkey)`
     * before calling this so the component already knows the address when verify() fires.
     */
    public function requestSignInChallenge(string $publicKey): array
    {
        return Socialite::driver('solana')->buildChallengeFor($publicKey);
    }

    public function signIn(string $signature, string $message, string $nonce): void
    {
        try {
            $solanaUser = Socialite::driver('solana')->verifyCredentials(
                $this->walletAddress, $signature, $message, $nonce,
            );
        } catch (SolanaAuthException $e) {
            $this->addError('solana', $e->getMessage());
            return;
        }

        // ... resolve user, log in, redirect
    }
}

use SanderMuller\SocialiteSolana\Exceptions\AddressMismatchException;
use SanderMuller\SocialiteSolana\Exceptions\ChallengeExpiredException;
use SanderMuller\SocialiteSolana\Exceptions\ChallengeNotFoundException;
use SanderMuller\SocialiteSolana\Exceptions\InvalidPublicKeyException;
use SanderMuller\SocialiteSolana\Exceptions\InvalidSignatureException;
use SanderMuller\SocialiteSolana\Exceptions\MalformedSignatureException;
use SanderMuller\SocialiteSolana\Exceptions\MessageMismatchException;
use SanderMuller\SocialiteSolana\Exceptions\MissingChallengeParameterException;

try {
    $solanaUser = Socialite::driver('solana')->user();
} catch (MissingChallengeParameterException) {
    return back()->withErrors(['wallet' => 'Wallet response was incomplete. Try again.']);
} catch (ChallengeExpiredException | ChallengeNotFoundException) {
    return back()->withErrors(['wallet' => 'Sign-in window expired. Click sign in to retry.']);
} catch (InvalidPublicKeyException) {
    return back()->withErrors(['wallet' => 'That wallet address is not a valid Solana public key.']);
} catch (MessageMismatchException | AddressMismatchException) {
    abort(400, 'Tampered request.'); // Wallet signed something the server did not issue — usually a bug, occasionally an attack.
} catch (MalformedSignatureException) {
    // Wallet returned a signature that's not 64 raw bytes — extension bug or wrong wallet. Catch BEFORE InvalidSignatureException.
    return back()->withErrors(['wallet' => 'Your wallet did not return a valid signature. Try a different wallet or reconnect.']);
} catch (InvalidSignatureException) {
    return back()->withErrors(['wallet' => 'Signature did not match. The user may have switched wallets mid-flow. Please try again.']);
}

// config/services.php
'solana' => [
    // ...
    'store' => 'cache',
],

use SanderMuller\SocialiteSolana\Contracts\ChallengeStore;

$this->app->singleton(ChallengeStore::class, MyRedisStore::class);

interface ChallengeStore
{
    public function put(Challenge $challenge): void;
    public function find(string $nonce): ?Challenge;
    public function forget(string $nonce): void;
}

use Illuminate\Support\Facades\Log;
use Laravel\Socialite\Facades\Socialite;
use SanderMuller\SocialiteSolana\Provider;

private function solanaProvider(): Provider
{
    /** @var Provider $provider */
    $provider = Socialite::driver('solana');

    $provider->setLogger(Log::channel('security'));

    return $provider;
}

// Use it like:
$user = $this->solanaProvider()->user();

// Avoid unless you actually want the routing to be app-wide:
$this->app->bind(\Psr\Log\LoggerInterface::class, fn () => Log::channel('security'));