PHP code example of sk-id-solutions / smart-id-php-client
1. Go to this page and download the library: Download sk-id-solutions/smart-id-php-client 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/ */
sk-id-solutions / smart-id-php-client example snippets
use Sk\SmartId\Api\SmartIdRestConnector;
use Sk\SmartId\Ssl\SslPinnedPublicKeyStore;
use Sk\SmartId\SmartIdClient;
use Sk\SmartId\Ssl\SslPinnedPublicKeyStore;
// Demo environment
$client = new SmartIdClient(
relyingPartyUUID: '00000000-0000-4000-8000-000000000000',
relyingPartyName: 'DEMO',
hostUrl: 'https://sid.demo.sk.ee/smart-id-rp/v3',
sslPinnedKeys: SslPinnedPublicKeyStore::loadDemo(),
);
// Production environment with logging (see "Logging" section below)
$sslKeys = SslPinnedPublicKeyStore::create()
->addPublicKeyHash('sha256//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=')
->addPublicKeyHash('sha256//YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY=');
$client = new SmartIdClient(
relyingPartyUUID: 'your-relying-party-uuid',
relyingPartyName: 'Your RP Name',
hostUrl: 'https://rp-api.smart-id.com/v3',
sslPinnedKeys: $sslKeys,
logger: $logger, // optional PSR-3 LoggerInterface
);
// Create authentication builders directly from the client
$deviceLinkBuilder = $client->createDeviceLinkAuthentication();
$notificationBuilder = $client->createNotificationAuthentication();
// Get the session status poller
$poller = $client->getSessionStatusPoller();
// Create validator (OCSP revocation checking is enabled automatically)
$validator = $client->createAuthenticationResponseValidator();
// Configure polling parameters (optional)
$client->setPollTimeoutMs(30000);
$client->setPollIntervalMs(1000);
use Sk\SmartId\Api\SmartIdRestConnector;
use Sk\SmartId\Ssl\SslPinnedPublicKeyStore;
// Demo environment
$connector = new SmartIdRestConnector(
'https://sid.demo.sk.ee/smart-id-rp/v3',
SslPinnedPublicKeyStore::loadDemo(),
);
// Production environment
$sslKeys = SslPinnedPublicKeyStore::create()
->addPublicKeyHash('sha256//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=')
->addPublicKeyHash('sha256//YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY=');
$connector = new SmartIdRestConnector('https://rp-api.smart-id.com/v3', $sslKeys);
$connector = new SmartIdRestConnector(
'https://sid.demo.sk.ee/smart-id-rp/v3',
SslPinnedPublicKeyStore::loadDemo(),
);
$sslKeys = SslPinnedPublicKeyStore::create()
->addPublicKeyHash('sha256//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=')
->addPublicKeyHash('sha256//YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY=');
$connector = new SmartIdRestConnector('https://rp-api.smart-id.com/v3', $sslKeys);
$sslKeys = SslPinnedPublicKeyStore::loadFromDirectory('/path/to/your/keys');
$connector = new SmartIdRestConnector('https://rp-api.smart-id.com/v3', $sslKeys);
$sslKeys = SslPinnedPublicKeyStore::fromString(getenv('SMARTID_SSL_PINS'));
$connector = new SmartIdRestConnector('https://rp-api.smart-id.com/v3', $sslKeys);
use Sk\SmartId\DeviceLink\DeviceLinkAuthenticationRequestBuilder;
use Sk\SmartId\Enum\CertificateLevel;
use Sk\SmartId\DeviceLink\DeviceLinkInteraction;
$builder = new DeviceLinkAuthenticationRequestBuilder(
$connector,
'00000000-0000-4000-8000-000000000000', // relyingPartyUUID
'DEMO', // relyingPartyName
);
// Initiate anonymous authentication (no user identifier needed)
$session = $builder
->withCertificateLevel(CertificateLevel::QUALIFIED)
->withAllowedInteractionsOrder([
DeviceLinkInteraction::displayTextAndPin('Log in to example.com'),
])
->initiate();
// Session ID for polling
$sessionId = $session->getSessionId();
// Verification code to display (if using notification-style interaction)
$verificationCode = $session->getVerificationCode();
// Build QR code URL (see "Generating QR code or device link" section)
$qrCodeUrl = $session->buildQrCodeUrl();
use Sk\SmartId\Util\RpChallengeGenerator;
$rpChallenge = RpChallengeGenerator::generate();
$session = $builder
->withRpChallenge($rpChallenge)
->withAllowedInteractionsOrder([
DeviceLinkInteraction::displayTextAndPin('Log in to example.com'),
])
->initiate();
use Sk\SmartId\DeviceLink\DeviceLinkAuthenticationRequest;
use Sk\SmartId\Enum\CertificateLevel;
use Sk\SmartId\Enum\HashAlgorithm;
use Sk\SmartId\DeviceLink\DeviceLinkInteraction;
use Sk\SmartId\Util\RpChallengeGenerator;
// For security, generate a new challenge for each request
$rpChallenge = RpChallengeGenerator::generate();
$interactions = [DeviceLinkInteraction::displayTextAndPin('Log in to example.com')];
$request = new DeviceLinkAuthenticationRequest(
relyingPartyUUID: '00000000-0000-4000-8000-000000000000',
relyingPartyName: 'DEMO',
rpChallenge: $rpChallenge,
hashAlgorithm: HashAlgorithm::SHA512,
allowedInteractionsOrder: $interactions,
certificateLevel: CertificateLevel::QUALIFIED,
);
$response = $connector->initiateDeviceLinkAuthentication($request);
// Store these on the backend for later use
$sessionId = $response->getSessionID();
$sessionToken = $response->getSessionToken();
$sessionSecret = $response->getSessionSecret(); // Keep secret, do not expose to client
$deviceLinkBase = $response->getDeviceLinkBase();
// Using the session object (simplest approach)
$session = $builder->initiate();
// QR code URL auto-calculates elapsed time from session creation
$qrCodeUrl = $session->buildQrCodeUrl();
// Or provide elapsed seconds explicitly
$qrCodeUrl = $session->buildQrCodeUrl(elapsedSeconds: 5);
$qrCodeUrl = $session->createDeviceLinkBuilder()
->withElapsedSeconds($elapsedSeconds)
->withDemoEnvironment() // for demo environment
->withLang('est') // override language
->buildQrCodeUrl();
use Sk\SmartId\Util\CallbackUrlUtil;
use Sk\SmartId\Util\CallbackUrlValidator;
// Validate and create callback URL with a cryptographically random token
$callbackBase = 'https://your-app.com/callback';
$callbackResult = CallbackUrlUtil::createCallbackUrl($callbackBase);
$callbackUrl = $callbackResult['callbackUrl']; // e.g., https://your-app.com/callback?value=<random-token>
$callbackToken = $callbackResult['token']; // Store to verify the callback later
// Callback URL must be set when initiating the session
$session = $builder
->withCallbackUrl($callbackUrl)
->withAllowedInteractionsOrder([
DeviceLinkInteraction::displayTextAndPin('Log in'),
])
->initiate();
$web2AppUrl = $session->buildWeb2AppUrl();
$builder = $session->createDeviceLinkBuilder()
->withDemoEnvironment() // override scheme for demo
->withLang('est') // override language
->withElapsedSeconds($elapsed);
$qrCodeUrl = $builder->buildQrCodeUrl();
$builder->withAllowedInteractionsOrder([
DeviceLinkInteraction::confirmationMessage('Up to 200 characters of text here..'),
DeviceLinkInteraction::displayTextAndPin('Up to 60 characters of text here..'),
]);
$builder->withAllowedInteractionsOrder([
DeviceLinkInteraction::confirmationMessage('Up to 200 characters of text here..'),
]);
use Sk\SmartId\Notification\NotificationAuthenticationRequestBuilder;
use Sk\SmartId\Notification\NotificationInteraction;
use Sk\SmartId\Enum\CertificateLevel;
use Sk\SmartId\Model\SemanticsIdentifier;
// Create semantics identifier:
// Type: PNO (personal number), PAS (passport), IDC (national identity card)
// Country: 2-letter ISO 3166-1 alpha-2 code
$semanticsIdentifier = SemanticsIdentifier::forPerson('EE', '30303039914');
// Or from a full string:
// $semanticsIdentifier = SemanticsIdentifier::fromString('PNOEE-30303039914');
$builder = new NotificationAuthenticationRequestBuilder(
$connector,
'00000000-0000-4000-8000-000000000000', // relyingPartyUUID
'DEMO', // relyingPartyName
);
$session = $builder
->withSemanticsIdentifier($semanticsIdentifier)
->withCertificateLevel(CertificateLevel::QUALIFIED)
->withAllowedInteractionsOrder([
NotificationInteraction::confirmationMessageAndVerificationCodeChoice('Log in to example.com'),
NotificationInteraction::displayTextAndPin('Log in to example.com'),
])
->initiate();
// Display verification code to the user
$verificationCode = $session->getVerificationCode();
// Use session ID to poll for status
$sessionId = $session->getSessionId();
$session = $builder
->withDocumentNumber('PNOLT-40504040001-MOCK-Q')
->withCertificateLevel(CertificateLevel::QUALIFIED)
->withAllowedInteractionsOrder([
NotificationInteraction::displayTextAndPin('Log in to example.com'),
])
->initiate();
$verificationCode = $session->getVerificationCode();
$sessionId = $session->getSessionId();
$builder->withAllowedInteractionsOrder([
NotificationInteraction::confirmationMessageAndVerificationCodeChoice('Up to 200 characters of text here...'),
NotificationInteraction::confirmationMessage('Up to 200 characters of text here...'),
NotificationInteraction::displayTextAndPin('Up to 60 characters of text here...'),
]);
$builder->withAllowedInteractionsOrder([
NotificationInteraction::confirmationMessageAndVerificationCodeChoice('Up to 200 characters of text here...'),
]);
use Sk\SmartId\Session\SessionStatusPoller;
$poller = new SessionStatusPoller($connector);
// Poll until session completes (blocks with long polling)
$sessionStatus = $poller->pollUntilComplete($sessionId);
if ($sessionStatus->isComplete()) {
$endResult = $sessionStatus->getResult()->getEndResult();
// 'OK' means authentication succeeded
}
$poller = new SessionStatusPoller($connector);
$poller->setPollTimeoutMs(30000); // Server-side long poll timeout (default: 30s)
$poller->setPollIntervalMs(1000); // Interval between poll attempts (default: 1s)
// Limit the number of poll attempts
$sessionStatus = $poller->pollUntilComplete($sessionId, maxAttempts: 60);
$poller = new SessionStatusPoller($connector);
$sessionStatus = $poller->poll($sessionId);
if ($sessionStatus->isRunning()) {
// Session still in progress — refresh QR code and poll again
} elseif ($sessionStatus->isComplete()) {
// Proceed to validation
}
use Sk\SmartId\Validation\TrustedCACertificateStore;
// Create via SmartIdClient (OCSP revocation checking is enabled automatically)
$validator = $client->createAuthenticationResponseValidator();
// PRODUCTION — load bundled certificates
TrustedCACertificateStore::loadFromDefaults()->configureValidator($validator);
// DEMO — load test certificates (upload certs to demo OCSP first, see "Uploading certificates to demo OCSP")
// TrustedCACertificateStore::loadTestCertificates()->configureValidator($validator);
// Custom directory
// TrustedCACertificateStore::loadFromDirectory('/path/to/certs')->configureValidator($validator);
// Manual certificates
// $store = TrustedCACertificateStore::create()
// ->addCertificate($pemEncodedCert)
// ->addCertificateFromFile('/path/to/cert.pem.crt');
// $store->configureValidator($validator);
use Sk\SmartId\Validation\TrustedCACertificateStore;
use Sk\SmartId\Enum\CertificateLevel;
use Sk\SmartId\Enum\SchemeName;
use Sk\SmartId\DeviceLink\DeviceLinkInteraction;
// Set up validator (demo environment — upload certs to demo OCSP first, see "Uploading certificates to demo OCSP")
$validator = $client->createAuthenticationResponseValidator();
TrustedCACertificateStore::loadTestCertificates()->configureValidator($validator);
// The interactions Base64 value must match what was sent in the original request
$interactions = [DeviceLinkInteraction::displayTextAndPin('Log in to example.com')];
// Initiate the authentication session
$session = $client->createDeviceLinkAuthentication()
->withRpChallenge($rpChallenge)
->withHashAlgorithm(HashAlgorithm::SHA512)
->withAllowedInteractionsOrder($interactions)
->initiate();
// The session now contains the pre-encoded interactions Base64 string
// This ensures the same encoding is used for both API requests and signature verification
$interactionsBase64 = $session->getInteractionsBase64();
// Validate and extract identity
$identity = $validator->validate(
$sessionStatus,
$rpChallenge, // Base64-encoded RP challenge from the original request
'DEMO', // Relying Party name
$interactionsBase64, // Base64-encoded interactions JSON from the session
// 1. Verify session secret from callback URL
$validator->verifySessionSecret(
$sessionSecret, // from the original session response
$sessionSecretDigest, // from the callback URL query parameter
);
// 2. Verify user challenge from callback URL
$validator->verifyUserChallenge(
$userChallengeVerifier, // from the callback URL query parameter
$userChallengeFromResponse, // from session status response signature.userChallenge
);
// 3. Then proceed with standard validation — pass the callback URL for Web2App signature verification
$identity = $validator->validate(
$sessionStatus,
$rpChallenge,
'DEMO',
$interactionsBase64,
$callbackUrl, // initialCallbackUrl used in Web2App flow
use Sk\SmartId\Util\CallbackUrlUtil;
// Generate a callback URL with a cryptographically random token
$result = CallbackUrlUtil::createCallbackUrl('https://your-app.com/callback');
$callbackUrl = $result['callbackUrl']; // e.g., https://your-app.com/callback?value=abc123...
$token = $result['token']; // Store this to verify the callback later
// Use the callback URL when initiating the session
$session = $builder
->withCallbackUrl($callbackUrl)
->withAllowedInteractionsOrder([...])
->initiate();
use Sk\SmartId\Util\CallbackUrlUtil;
// Throws ValidationException if digest does not match
CallbackUrlUtil::validateSessionSecretDigest(
$sessionSecretDigest, // from the callback URL query parameter
$sessionSecret, // from the original session init response
);
$identity->getGivenName(); // e.g., 'QUALIFIED OK1'
$identity->getSurname(); // e.g., 'TESTNUMBER'
$identity->getFullName(); // e.g., 'QUALIFIED OK1 TESTNUMBER'
$identity->getIdentityCode(); // e.g., '30303039914'
$identity->getCountry(); // e.g., 'EE'
// Additional methods for Baltic states (EE, LV, LT):
$identity->getDateOfBirth(); // DateTimeImmutable or null
$identity->getGender(); // 'M', 'F', or null
$identity->getAge(); // int or null
// Device link authentication with IP address sharing
$session = $builder
->withCertificateLevel(CertificateLevel::QUALIFIED)
->withAllowedInteractionsOrder([
DeviceLinkInteraction::displayTextAndPin('Log in to example.com'),
])
->withShareMdClientIpAddress()
->initiate();
// After session completes, retrieve the device IP address
$sessionStatus = $poller->pollUntilComplete($session->getSessionId());
$deviceIpAddress = $sessionStatus->getDeviceIpAddress(); // IP address or null
use Sk\SmartId\Exception\SmartIdException;
use Sk\SmartId\Exception\UserRefusedException;
use Sk\SmartId\Exception\UserRefusedInteractionException;
use Sk\SmartId\Exception\SessionTimeoutException;
use Sk\SmartId\Exception\WrongVerificationCodeException;
use Sk\SmartId\Exception\UserAccountException;
use Sk\SmartId\Exception\DocumentUnusableException;
use Sk\SmartId\Exception\RequiredInteractionNotSupportedException;
use Sk\SmartId\Exception\ProtocolFailureException;
use Sk\SmartId\Exception\ServerErrorException;
use Sk\SmartId\Exception\ValidationException;
use Sk\SmartId\Exception\UnderMaintenanceException;
try {
$sessionStatus = $poller->pollUntilComplete($sessionId);
$identity = $validator->validate($sessionStatus, ...);
} catch (SessionTimeoutException $e) {
// User did not respond in time
} catch (UserRefusedInteractionException $e) {
// User refused a specific interaction — check which one
$interaction = $e->getInteraction(); // e.g., 'displayTextAndPIN'
} catch (UserRefusedException $e) {
// User refused the operation (covers USER_REFUSED and all USER_REFUSED_* variants)
} catch (WrongVerificationCodeException $e) {
// User selected wrong verification code
} catch (DocumentUnusableException $e) {
// Document is unusable for this operation
} catch (RequiredInteractionNotSupportedException $e) {
// Required interaction not supported by user's app
} catch (UserAccountException $e) {
if ($e->isNoSuitableAccount()) {
// No suitable Smart-ID account
} elseif ($e->isPersonShouldViewApp()) {
// User should check Smart-ID app
} elseif ($e->isClientTooOld()) {
// Client-side API too old
}
} catch (ProtocolFailureException $e) {
// Protocol failure — retry may help
} catch (ServerErrorException $e) {
// Smart-ID server error — retry later
} catch (ValidationException $e) {
// Authentication response validation failed — do not trust!
} catch (UnderMaintenanceException $e) {
// System is under maintenance (HTTP 580) — retry later
} catch (SmartIdException $e) {
// General Smart-ID error (
use Psr\Log\LoggerInterface;
use Sk\SmartId\SmartIdClient;
use Sk\SmartId\Ssl\SslPinnedPublicKeyStore;
// Example with Monolog
$logger = new \Monolog\Logger('smart-id');
$logger->pushHandler(new \Monolog\Handler\StreamHandler('php://stderr', \Monolog\Level::Debug));
$client = new SmartIdClient(
relyingPartyUUID: '00000000-0000-4000-8000-000000000000',
relyingPartyName: 'DEMO',
hostUrl: 'https://sid.demo.sk.ee/smart-id-rp/v3',
sslPinnedKeys: SslPinnedPublicKeyStore::loadDemo(),
logger: $logger,
);
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.