Search by

gam6itko / oauth2-vk-id

gam6itko

VK ID (OAuth 2.1, id.vk.ru) provider for league/oauth2-client — PKCE, device_id, no superglobals (RoadRunner/Swoole-safe).

Package info

github.com/gam6itko/oauth2-vk-id

pkg:composer/gam6itko/oauth2-vk-id

Statistics

Installs: 4

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.1.0 2026-09-15 20:43 UTC

This package is auto-updated.

Last update: 2026-09-15 20:46:04 UTC


README

VK ID (OAuth 2.1, id.vk.ru) provider for The PHP League OAuth2 Client.

See the official VK ID web auth flow docs for the underlying protocol.

Unlike the other oauth2-vkontakte packages on Packagist:

  • it targets the new VK ID endpoints (id.vk.ru), not the deprecated oauth.vk.com / api.vk.com OAuth 2.0;
  • it keeps no hidden state — it never reads or writes $_SESSION / $_GET, so it works under long-running workers (RoadRunner, Swoole, FrankenPHP), not just PHP-FPM.

Installation

composer require gam6itko/oauth2-vk-id

Requires PHP 8.1+ and league/oauth2-client ^2.7 (native PKCE).

Why the two VK-specific quirks are your job

VK ID adds two things on top of a plain Authorization Code flow. This library enables them the league-idiomatic way and leaves persistence to you, so nothing is hidden in globals:

  1. PKCE is mandatory. The provider returns S256 from getPkceMethod(), so league generates the code_challenge for the authorize URL and appends the code_verifier to the token exchange for you. Because the verifier must survive the browser redirect, you persist it with getPkceCode() / setPkceCode() (session, cache, DB — wherever your framework keeps request state).
  2. device_id is returned by VK on the callback and required for the token exchange. Forward it as a plain option: getAccessToken('authorization_code', ['code' => $code, 'device_id' => $deviceId]).

Usage

use Gam6itko\OAuth2\Client\Provider\VkId;

$provider = new VkId([
    'clientId'     => '<VK app id>',
    'clientSecret' => '',                 // empty for a public PKCE client
    'redirectUri'  => 'https://example.org/login/vk/callback',
    'scopes'       => 'vkid.personal_info email', // string or array; default: vkid.personal_info
]);

// 1. Start: build the authorize URL and stash state + PKCE verifier wherever your request state lives.
$authUrl = $provider->getAuthorizationUrl();
$store->set('vk_state', $provider->getState());
$store->set('vk_pkce', $provider->getPkceCode());
header('Location: ' . $authUrl);
exit;

// 2. Callback: verify state, restore the PKCE verifier, exchange the code (with device_id).
if ($_GET['state'] !== $store->get('vk_state')) {
    exit('Invalid state');
}
$provider->setPkceCode($store->get('vk_pkce'));

$token = $provider->getAccessToken('authorization_code', [
    'code'      => $_GET['code'],
    'device_id' => $_GET['device_id'],
]);

/** @var \Gam6itko\OAuth2\Client\Provider\VkIdResourceOwner $owner */
$owner = $provider->getResourceOwner($token);

$owner->getId();        // stable VK user id (string) — use as the provider key
$owner->getFirstName();
$owner->getLastName();
$owner->getEmail();     // only with the `email` scope, else null
$owner->getPhone();     // only with the `phone` scope, else null
$owner->getAvatar();
$owner->toArray();

$store above is a placeholder for whatever holds per-request state in your app (PSR-16 cache, a framework session, etc.). The library deliberately does not choose one for you.

Scopes

  • vkid.personal_info — name, gender, avatar, birthday (default, always available).
  • email — populates getEmail().
  • phone — populates getPhone().

License

MIT. See LICENSE.