No release in over 3 years
Simple Ruby library for authenticating users with Estonian ID cards using local card readers.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

~> 0.3
 Project Readme

Estonian ID Card Authentication Library

Ruby library for Estonian ID card authentication supporting both local card readers and Web eID browser-based authentication.

Authentication Methods

Supported Methods:

  • Local DigiDoc - Direct card reader access via PKCS#11
  • Web eID - Browser-based authentication using Web eID extension
  • Mobile-ID - Not yet implemented
  • Smart-ID - Not yet implemented

Local vs Web eID:

  • Local: Requires card reader connected to server, works offline
  • Web eID: Uses browser extension, works remotely, requires HTTPS

Overview

Identity verification is fundamental to secure digital interactions. This library provides a robust, production-ready interface to Estonian e-identity infrastructure—one of the most advanced digital identity systems in the world—enabling bulletproof authentication for Ruby applications.

The library seamlessly integrates:

  • Hardware Security Modules (HSM) embedded in Estonian ID cards
  • PKCS#11 cryptographic interface (industry-standard smart card communication)
  • X.509 certificate infrastructure (PKI-based digital trust)
  • Estonian personal identification system (comprehensive demographic encoding)

Why Estonian ID Cards?

Estonia pioneered digital identity in 2002, creating the world's first nationwide public key infrastructure. Today, 99% of Estonians possess digital identity, making it the most digitally advanced society globally. Estonian ID cards provide:

  • Government-issued PKI certificates with legal validity
  • Hardware security modules for tamper-resistant key storage
  • Standardized PKCS#11 interface for broad compatibility
  • Comprehensive personal data encoding in certificate fields
  • Mature ecosystem with 20+ years of real-world usage

This library provides production-ready access to this proven infrastructure for Ruby applications.

Key Features

🛡️ Enterprise-Grade Security

  • Hardware-based cryptography: All operations occur within the card's tamper-resistant secure element
  • PIN verification on-chip: PINs never leave the card, preventing interception
  • Certificate-based authentication: Uses X.509 certificates signed by Estonian government CA
  • Session management: Timeout-based sessions prevent unauthorized access
  • PKCS#11 compliance: Industry standard cryptographic interface

🔬 Comprehensive Data Extraction

  • Complete demographic parsing: Birth date, gender, age calculation with precision
  • Estonian personal code decoding: Mathematical algorithm covering 4 centuries (1800-2199)
  • Certificate field mapping: Extracts all available personal information
  • Unicode support: Handles Estonian characters and international names flawlessly

⚡ High Performance

  • Lazy loading: PKCS#11 libraries loaded only when needed
  • Shared instances: Prevents resource conflicts in multi-process environments
  • Memory efficient: Minimal footprint suitable for embedded systems
  • Error resilient: Graceful handling of hardware failures and user errors

🔧 Exceptional Developer Experience

  • Simple API: Authentication in 3 lines of code
  • Comprehensive testing: Unit tests, integration tests, hardware tests
  • Rich documentation: Every method thoroughly documented
  • Make-based workflow: Streamlined development commands

System Architecture

Component Architecture

                    Application Layer
                         |
                    EeIdVerification
                    /        |        \
              Verifier    Models    CertificateReader
                    |         |            |
                    |     Sessions      PKCS#11
                    |     Results         |
                    |         |         OpenSC
                    |         |           |
                    └─────────┴───────Estonian ID Card

Core Components

Main Module (EeIdVerification)

The primary API interface that coordinates all components while maintaining a clean, simple interface for applications.

Verifier (EeIdVerification::Verifier)

Orchestrates the authentication workflow, managing the complete lifecycle from card detection to personal data extraction.

Certificate Reader (EeIdVerification::CertificateReader)

Handles low-level PKCS#11 communication with Estonian ID cards. Contains the complex smart card interaction logic.

Data Models (EeIdVerification::Models)

Structured data representations:

  • AuthenticationSession: Tracks authentication state and timeout management
  • AuthenticationResult: Contains authentication outcome and extracted personal data

PKCS#11 Interface

Provides the bridge between Ruby and the hardware security module using OpenSC drivers for smart card communication.

Installation

Prerequisites

Before installation, ensure your system has the necessary components:

macOS

# Install OpenSC for PKCS#11 support
brew install opensc

# Verify installation
pkcs11-tool --list-slots

Linux

# Ubuntu/Debian
sudo apt-get install opensc-pkcs11

# CentOS/RHEL/Fedora
sudo yum install opensc

# Verify installation
pkcs11-tool --list-slots

Hardware Requirements

  • Card Reader: Any PC/SC compatible smart card reader
  • Estonian ID Card: Valid Estonian identity card (issued 2014 or later recommended)
  • USB Connection: Stable connection for reliable operation

Gem Installation

# Add to your Gemfile (recommended)
gem 'ee-id-verification', '~> 1.0'

# Or install directly
gem install ee-id-verification

# For development
git clone https://github.com/yourusername/EE-ID-verification.git
cd EE-ID-verification
bundle install

Quick Start

Local Card Authentication

require 'ee_id_verification'

# Create verifier instance
verifier = EeIdVerification.new

# Check if Estonian ID card is present
if verifier.available?
  puts "Estonian ID card detected!"
  
  # Start authentication
  session = verifier.authenticate
  puts "Please enter your PIN1:"
  
  pin = gets.chomp
  result = verifier.complete_authentication(session, pin)
  
  if result.success?
    puts "Welcome, #{result.full_name}!"
    puts "Personal code: #{result.personal_code}"
    puts "Country: #{result.country}"
  else
    puts "Authentication failed: #{result.error}"
  end
else
  puts "No Estonian ID card detected. Please insert card and try again."
end

Web eID Authentication

require 'ee_id_verification'

# Server-side: Generate challenge
challenge_nonce = SecureRandom.base64(32)

# Client-side: Use web-eid.js to get auth token
# const authToken = await webeid.authenticate(challengeNonce)

# Server-side: Verify the authentication token
verifier = EeIdVerification::WebEidVerifier.new
result = verifier.verify_auth_token(auth_token, challenge_nonce)

if result.success?
  puts "Welcome, #{result.full_name}!"
  puts "Personal code: #{result.personal_code}"
else
  puts "Authentication failed: #{result.error}"
end

Web eID Test Application

Test Web eID authentication with a full web interface:

# Launch Web eID test app with HTTPS tunnel
make webeid_test

# Or manually:
cd test/web_app
./start.sh

The Web eID test application provides:

  • HTTPS tunnel via Cloudflare for Web eID compatibility
  • Interactive web interface for testing authentication
  • Real ID card integration with certificate reading
  • Complete authentication flow demonstration

Advanced Example

require 'ee_id_verification'

class EstonianAuthenticationSystem
  def initialize
    @verifier = EeIdVerification.new
  end
  
  def perform_authentication
    # Step 1: Card Detection
    unless card_detected?
      return authentication_failed("No Estonian ID card detected")
    end
    
    # Step 2: Create Session
    session = @verifier.authenticate
    log_session_created(session)
    
    # Step 3: Collect PIN with timeout handling
    pin = collect_pin_with_timeout(session)
    return authentication_failed("Session expired") if session.expired?
    
    # Step 4: Complete Authentication
    result = @verifier.complete_authentication(session, pin)
    
    # Step 5: Process Result
    process_authentication_result(result)
  end
  
  private
  
  def card_detected?
    @verifier.available?
  end
  
  def collect_pin_with_timeout(session, timeout = 300)
    puts "🔐 Enter your PIN1 (#{timeout} seconds remaining):"
    
    # In real applications, use proper timeout mechanism
    pin = gets.chomp
    
    # Validate PIN format (Estonian PINs are typically 4-12 digits)
    unless pin.match?(/^\d{4,12}$/)
      puts "⚠️ Invalid PIN format. Estonian PINs are 4-12 digits."
      return collect_pin_with_timeout(session, timeout)
    end
    
    pin
  end
  
  def process_authentication_result(result)
    if result.success?
      log_successful_authentication(result)
      welcome_user(result)
      extract_additional_data(result)
    else
      log_authentication_failure(result)
      handle_authentication_error(result)
    end
  end
  
  def extract_additional_data(result)
    reader = EeIdVerification::CertificateReader.new
    personal_info = reader.parse_personal_code(result.personal_code)
    
    puts "\nDemographic Information:"
    puts "   Birth Date: #{personal_info[:birth_date]}"
    puts "   Gender: #{personal_info[:gender]}"
    puts "   Age: #{personal_info[:age]} years"
    puts "   Generation: #{determine_generation(personal_info[:birth_date])}"
  end
  
  def determine_generation(birth_date)
    case birth_date.year
    when 1946..1964 then "Baby Boomer"
    when 1965..1980 then "Generation X"
    when 1981..1996 then "Millennial"
    when 1997..2012 then "Generation Z"
    else "Generation Alpha"
    end
  end
  
  def log_session_created(session)
    puts "📡 Session #{session.id} created at #{session.created_at}"
  end
  
  def log_successful_authentication(result)
    puts "✅ Authentication successful for #{result.personal_code}"
  end
  
  def log_authentication_failure(result)
    puts "❌ Authentication failed: #{result.error}"
  end
  
  def welcome_user(result)
    puts "\nWelcome, #{result.full_name}!"
    puts "Successfully authenticated from #{result.country}"
  end
  
  def handle_authentication_error(result)
    case result.error
    when /PIN/i
      puts "🔒 PIN-related error. Please check your PIN1 and try again."
      puts "⚠️ Remember: 3 failed attempts will block your PIN!"
    when /card/i
      puts "🎴 Card-related error. Please check card insertion and reader connection."
    when /certificate/i
      puts "Certificate error. Your card may be expired or damaged."
    else
      puts "Unknown error: #{result.error}"
    end
  end
  
  def authentication_failed(reason)
    puts "Authentication failed: #{reason}"
    false
  end
end

# Run the authentication
system = EstonianAuthenticationSystem.new
system.perform_authentication

Testing

This library includes comprehensive testing at multiple levels:

Unit Tests

# Run basic unit tests (no hardware required)
make test

# Or directly with Ruby
bundle exec ruby -Ilib:test test/ee_id_verification_test.rb

Integration Tests

# Run tests with actual Estonian ID card
make test_hardware

# Or with environment variable
HARDWARE_TESTS=1 bundle exec ruby -Ilib:test test/ee_id_verification_test.rb

Interactive Tests

# Interactive test with your Estonian ID card
make run_local_card_test

# Shows real-time card detection and authentication

Development Commands

Available Make Targets

The included Makefile provides comprehensive development commands:

# Show all available commands
make help

# Install dependencies
make install

# Run unit tests only
make test

# Run complete test suite with hardware
make test_hardware

# Interactive card test
make run_local_card_test

# Launch Web eID test application
make webeid_test

# Build gem package
make build

# Clean build artifacts
make clean

API Reference

Core Components

EeIdVerification.new

Creates a new verifier instance for Estonian ID card authentication.

verifier = EeIdVerification.new

verifier.available?

Checks if an Estonian ID card is present and ready for authentication.

if verifier.available?
  puts "Card detected!"
end

verifier.authenticate

Initiates authentication process and returns a session.

session = verifier.authenticate
# Returns: AuthenticationSession with unique ID and timeout

verifier.complete_authentication(session, pin)

Completes authentication using the provided PIN1.

result = verifier.complete_authentication(session, "1234")

if result.success?
  puts "Name: #{result.full_name}"
  puts "Personal Code: #{result.personal_code}"
  puts "Country: #{result.country}"
end

Personal Code Parsing

reader = EeIdVerification::CertificateReader.new
info = reader.parse_personal_code("38001010008")

puts "Birth Date: #{info[:birth_date]}"  # 1980-01-01
puts "Gender: #{info[:gender]}"          # Male
puts "Age: #{info[:age]}"                # Current age

Troubleshooting

Common Issues and Solutions

"PKCS#11 library not found"

# macOS
brew install opensc

# Ubuntu/Debian
sudo apt-get install opensc-pkcs11

# Verify installation
find /usr -name "*opensc-pkcs11*" 2>/dev/null

"No Estonian ID card found"

  • Ensure card is properly inserted
  • Check card reader connection
  • Verify card reader drivers are installed
  • Try restarting PC/SC service

"Invalid PIN1"

  • Verify PIN1 (not PIN2 for signing)
  • Check if PIN is blocked (3 failed attempts)
  • Use DigiDoc4 to unblock if needed

Performance Issues

  • Check USB connection quality
  • Ensure no other applications are accessing the card
  • Verify card reader compatibility

Diagnostic Script

Create a comprehensive diagnostic:

#!/usr/bin/env ruby
require 'ee_id_verification'

puts "Estonian ID Card Diagnostics"
puts "=" * 40

# Check system dependencies
puts "\nSystem Dependencies:"
puts "OpenSC: #{`which opensc-tool`.strip.empty? ? 'Not found' : 'Found'}"
puts "PC/SC: #{`which pcsc_scan`.strip.empty? ? 'Not found' : 'Found'}"

# Check PKCS#11 library
puts "\nPKCS#11 Library:"
begin
  reader = EeIdVerification::CertificateReader.new
  library = reader.class.shared_pkcs11_library
  puts "Library: #{library ? 'Found' : 'Missing'}"
rescue => e
  puts "Error: #{e.message}"
end

# Check card detection
puts "\nCard Detection:"
begin
  verifier = EeIdVerification.new
  detected = verifier.available?
  puts "Estonian ID card: #{detected ? 'Detected' : 'Not found'}"
rescue => e
  puts "Error: #{e.message}"
end

puts "\nDiagnostics complete!"

Security Considerations

Production Security Checklist

  • Use HTTPS for all communications
  • Implement proper session management
  • Enable audit logging
  • Set up rate limiting
  • Validate all input parameters
  • Use secure session storage
  • Implement CSRF protection
  • Regular security updates

Hardware Security

  • Verify card reader authenticity
  • Ensure physical security
  • Monitor for tampering
  • Use certified PKCS#11 libraries

Contributing

We welcome contributions from all developers!

Development Setup

git clone https://github.com/yourusername/EE-ID-verification.git
cd EE-ID-verification
bundle install
make test

Code Style

  • Follow Ruby Style Guide
  • Add comprehensive documentation
  • Include tests for all changes
  • Use descriptive commit messages

Pull Request Process

  1. Fork and create feature branch
  2. Make changes with tests
  3. Update documentation
  4. Submit pull request with description

Performance

Benchmarks

  • Card detection: ~50ms average
  • Authentication: ~200ms with PIN entry
  • Personal code parsing: <1ms
  • Memory usage: <10MB

Optimization Tips

  • Use connection pooling for high-volume applications
  • Implement caching for repeated operations
  • Consider async processing for batch operations

Production Examples

Web Application Integration

Web eID (Recommended for web apps)

# Rails controller example
class AuthController < ApplicationController
  def challenge
    nonce = SecureRandom.base64(32)
    session[:nonce] = nonce
    session[:nonce_created_at] = Time.now.to_i
    
    render json: { nonce: nonce }
  end
  
  def login
    auth_token = params[:authToken]
    stored_nonce = session[:nonce]
    
    return render json: { error: "No challenge nonce" } unless stored_nonce
    
    if Time.now.to_i - session[:nonce_created_at] > 300
      return render json: { error: "Challenge expired" }
    end
    
    verifier = EeIdVerification::WebEidVerifier.new
    result = verifier.verify_auth_token(auth_token, stored_nonce)
    
    if result.success?
      session[:user_id] = find_or_create_user(result).id
      render json: { success: true, user: { name: result.full_name } }
    else
      render json: { error: result.error }
    end
  end
end

Local Card Authentication

Note: For local card auth, the card reader must be connected to the server.

class LocalAuthController < ApplicationController
  def initiate
    verifier = EeIdVerification.new
    
    unless verifier.available?
      return render json: { 
        error: "No Estonian ID card detected on server"
      }
    end
    
    session = verifier.authenticate
    session[:auth_session_id] = session.id
    
    render json: { session_id: session.id }
  end
  
  def complete
    # ... PIN verification logic
  end
end

Docker Deployment

Note: Docker containers need special configuration for USB device access (card readers).

FROM ruby:3.2-slim

# Install PKCS#11 and smart card dependencies
RUN apt-get update && apt-get install -y \
    opensc-pkcs11 \
    pcscd \
    pcsc-tools \
    libpcsclite-dev \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY Gemfile* ./
RUN bundle install

COPY . .

# Start PC/SC daemon and run application
CMD service pcscd start && bundle exec ruby app.rb
# docker-compose.yml
version: '3.8'
services:
  estonian-auth:
    build: .
    ports:
      - "3000:3000"
    devices:
      - /dev/bus/usb:/dev/bus/usb  # USB card reader access
    privileged: true  # Required for smart card hardware access
    environment:
      - RAILS_ENV=production

Use Cases

Government Services

  • Citizen portals: Secure access to government services
  • Tax systems: Electronic tax filing and declarations
  • Social services: Benefit applications and status checking
  • Municipal services: Local government service access
  • Legal systems: Court filing and case management

Financial Services

  • Banking authentication: Secure login for online banking
  • Loan processing: Identity verification for applications
  • Insurance claims: Policyholder authentication
  • Investment platforms: KYC compliance and account access
  • Payment systems: High-value transaction authorization

Healthcare

  • Patient portals: Access to medical records and test results
  • Prescription systems: Electronic prescription management
  • Appointment booking: Secure healthcare service scheduling
  • Insurance verification: Healthcare benefit verification
  • Telemedicine: Patient identity verification for remote consultations

Enterprise & Education

  • Employee authentication: Secure access to corporate systems
  • Student portals: Academic record access and course enrollment
  • Document signing: Legally binding electronic signatures
  • Time & attendance: Secure employee time tracking
  • Access control: Physical and logical access management

Integration Scenarios

  • API authentication: Service-to-service authentication
  • Single sign-on: Enterprise SSO integration
  • Multi-factor auth: Strong second factor for critical systems
  • Audit trails: Compliance and regulatory reporting
  • Identity federation: Cross-organizational authentication

Additional Resources

Documentation

Support

Community

  • GitHub Issues: Report bugs and feature requests
  • Discussions: Share experiences and get help
  • Stack Overflow: Tag questions with estonian-id

License

MIT License - See LICENSE file for details.

Acknowledgments

  • Republic of Estonia: For pioneering digital identity
  • SK ID Solutions: For Estonian ID card infrastructure
  • OpenSC Project: For PKCS#11 drivers
  • Ruby Community: For the excellent ecosystem
  • Contributors: Everyone who helped improve this library

About

This gem has been developed by Sorbeet Payments OU (commercial name "Sorbet").

For any inquiries, please contact Angelos at angelos@sorbet.ee


"The best way to predict the future is to invent it." — Alan Kay

Estonia invented the future of digital identity. This library helps you build on that foundation and create applications that demonstrate how secure, convenient digital identity should work everywhere.

Welcome to the future of authentication. Welcome to Estonian digital identity.