sarkhanrasimoghlu/laravel-asanimza

Laravel package for Asan İmza mobile authentication and digital signing via JSON-RPC 2.0 proxy API

Maintainers

Package info

github.com/Rasimoghlu/laravel-asanimza

pkg:composer/sarkhanrasimoghlu/laravel-asanimza

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-03-16 09:37 UTC

This package is auto-updated.

Last update: 2026-03-16 09:41:47 UTC


README

Laravel package for Asan İmza — Azerbaijan's mobile authentication and digital signing system. Communicates with the Asan İmza proxy server via JSON-RPC 2.0 protocol.

Requirements

  • PHP ^8.3
  • Laravel ^12.0
  • Asan İmza proxy server running (default: http://localhost:8090)

Installation

composer require sarkhanrasimoghlu/laravel-asanimza

Publish the configuration file:

php artisan vendor:publish --tag=asanimza-config

Configuration

Add the following to your .env file:

ASANIMZA_BASE_URL=http://localhost:8090
ASANIMZA_SERVICE_NAME=AsanDoc
ASANIMZA_LANGUAGE=aze
ASANIMZA_TIMEOUT=30
ASANIMZA_LOG_ENABLED=true
ASANIMZA_LOG_CHANNEL=stack
Variable Default Description
ASANIMZA_BASE_URL http://localhost:8090 Asan İmza proxy server URL
ASANIMZA_SERVICE_NAME AsanDoc Registered service name
ASANIMZA_LANGUAGE aze Default language (aze, rus, eng)
ASANIMZA_TIMEOUT 30 HTTP request timeout (seconds)
ASANIMZA_LOG_ENABLED true Enable/disable request logging
ASANIMZA_LOG_CHANNEL stack Laravel log channel

Usage

Inject AsanImzaInterface via constructor or method injection:

use Sarkhanrasimoghlu\AsanImza\Contracts\AsanImzaInterface;

Authentication

Step 1: Start authentication

public function login(AsanImzaInterface $asanImza)
{
    $result = $asanImza->authenticate('+994501234567', 'userId123');

    // Show verification code to the user
    // $result->verificationCode — user must confirm this on their phone
    // $result->transactionId — needed for status check
    // $result->certificate — needed for status check
    // $result->challenge — needed for status check

    return response()->json([
        'transactionId' => $result->transactionId,
        'verificationCode' => $result->verificationCode,
        'certificate' => $result->certificate,
        'challenge' => $result->challenge,
    ]);
}

Step 2: Check authentication status (polling)

public function checkAuth(AsanImzaInterface $asanImza, Request $request)
{
    $status = $asanImza->getAuthStatus(
        transactionId: $request->input('transactionId'),
        certificate: $request->input('certificate'),
        challenge: $request->input('challenge'),
    );

    if ($status->status === \Sarkhanrasimoghlu\AsanImza\Enums\AuthStatus::USER_AUTHENTICATED) {
        // Authentication successful
        // $status->signature contains the base64-encoded signature
    }

    return response()->json([
        'status' => $status->status->value,
    ]);
}

Get Certificate Data

Extract user information from a certificate:

$certData = $asanImza->getCertificateData($certificate);

$certData->firstName;       // "John"
$certData->surname;         // "Doe"
$certData->personalCode;    // "1234567"
$certData->organizationName; // nullable
$certData->certType;        // CertType enum (AUTHENTICATION, CITIZEN_SIGNING, etc.)

Digital Signing

Step 1: Get signing certificates

$certs = $asanImza->getSigningCertificates('+994501234567', 'userId123');
// Returns: ['certId1' => 'base64cert1', 'certId2' => 'base64cert2']

Step 2: Sign files

use Sarkhanrasimoghlu\AsanImza\DTOs\DataFile;

$dataFiles = [
    new DataFile(
        content: base64_encode(file_get_contents('/path/to/document.pdf')),
        fileName: 'document.pdf',
        mimeType: 'application/pdf',
    ),
];

$result = $asanImza->signFiles(
    dataFiles: $dataFiles,
    phoneNumber: '+994501234567',
    userId: 'userId123',
    certIdentifier: 'certId1',
    certificate: $certs['certId1'],
);

// $result->transactionId
// $result->verificationCode — show to user
// $result->hash — needed for status check
// $result->container — needed for status check

Step 3: Check signing status (polling)

$status = $asanImza->getSignFileStatus(
    transactionId: $result->transactionId,
    hash: $result->hash,
    container: $result->container,
    certificate: $certs['certId1'],
);

if ($status->status === \Sarkhanrasimoghlu\AsanImza\Enums\SignStatus::SIGNATURE_CREATED) {
    // $status->container — signed container (base64)
    $signedContent = base64_decode($status->container);
}

Error Handling

All exceptions extend AsanImzaException:

use Sarkhanrasimoghlu\AsanImza\Exceptions\AsanImzaException;
use Sarkhanrasimoghlu\AsanImza\Exceptions\JsonRpcException;

try {
    $result = $asanImza->authenticate('+994501234567', 'userId123');
} catch (JsonRpcException $e) {
    // JSON-RPC error from Asan İmza proxy
    $e->getErrorCode();    // e.g., 2004
    $e->getErrorMessage(); // e.g., "Unknown phone number"
    $e->getContext();      // ['error_code' => 2004, 'error_message' => '...']
} catch (AsanImzaException $e) {
    // HTTP or parsing error
    $e->getMessage();
    $e->getContext();
}

Common Error Codes

Code Description
1002 Service overloaded
2004 Unknown phone number
2013 No authentication certificate
2017 Phone number and user ID are not related
2018 Authentication certificate is not valid
2020 No signing certificate
2021 Signing certificate is not valid
2022 Forbidden service name
-32700 JSON-RPC parse error
-32600 Invalid request
-32601 Method not found

Enums

AuthStatus

Value Description
USER_AUTHENTICATED Authentication successful
OUTSTANDING_TRANSACTION Waiting for user confirmation
NOT_VALID Transaction not valid
EXPIRED_TRANSACTION Transaction expired
USER_CANCEL User cancelled on phone
MID_NOT_READY Mobile ID not ready
SENDING_ERROR Error sending to phone
SIM_ERROR SIM card error
INTERNAL_ERROR Internal system error

SignStatus

Same values as AuthStatus, except USER_AUTHENTICATED is replaced by SIGNATURE_CREATED.

CertType

Value Description
0 Authentication
1 Citizen signing
2 Business signing
3 Governmental signing
4 Youth personal
5 Digital stamp

License

MIT