mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-18 19:12:54 +00:00
- Add README.md with installation instructions, architecture overview, and API examples for all SDK modules - Refactor TelecomSDK::Client to use modular API clients (SubscriberAPI, UsageAPI, PaymentAPI, RatingPlanAPI, SystemAPI, GraphQLAPI) - Add AuthProvider class with API key and JWT token support (generate_jwt_token, validate_jwt_token methods) - Add HTTPClient base class with retry
112 lines
2.9 KiB
Ruby
112 lines
2.9 KiB
Ruby
require "openssl"
|
|
require "base64"
|
|
require "json"
|
|
|
|
module TelecomSDK
|
|
# Authentication provider for the Telecom SDK
|
|
class AuthProvider
|
|
attr_reader :api_key, :jwt_secret, :token_cache, :token_expiry
|
|
|
|
def initialize(api_key: nil, jwt_secret: nil)
|
|
@api_key = api_key
|
|
@jwt_secret = jwt_secret
|
|
@token_cache = nil
|
|
@token_expiry = nil
|
|
end
|
|
|
|
# Get authentication headers for API requests
|
|
def get_headers
|
|
headers = {
|
|
"Content-Type" => "application/json",
|
|
"User-Agent" => "Telecom-Ruby-SDK/1.0.0"
|
|
}
|
|
|
|
headers["X-API-Key"] = @api_key if @api_key
|
|
|
|
if @token_cache && token_valid?
|
|
headers["Authorization"] = "Bearer #{@token_cache}"
|
|
end
|
|
|
|
headers
|
|
end
|
|
|
|
# Generate a JWT token for authentication
|
|
def generate_jwt_token(user_id, expiry_hours = 24, additional_claims = {})
|
|
raise AuthenticationError, "JWT secret not configured" unless @jwt_secret
|
|
|
|
now = Time.now.to_i
|
|
exp = now + (expiry_hours * 3600)
|
|
|
|
claims = {
|
|
"sub" => user_id,
|
|
"exp" => exp,
|
|
"iat" => now
|
|
}.merge(additional_claims)
|
|
|
|
header = { "alg" => "HS256", "typ" => "JWT" }
|
|
|
|
encoded_header = base64_url_encode(header)
|
|
encoded_payload = base64_url_encode(claims)
|
|
signature = sign("#{encoded_header}.#{encoded_payload}")
|
|
|
|
@token_cache = "#{encoded_header}.#{encoded_payload}.#{signature}"
|
|
@token_expiry = exp
|
|
|
|
@token_cache
|
|
end
|
|
|
|
# Validate a JWT token
|
|
def validate_jwt_token(token)
|
|
raise AuthenticationError, "JWT secret not configured" unless @jwt_secret
|
|
|
|
parts = token.split(".")
|
|
raise AuthenticationError, "Invalid token format" if parts.size != 3
|
|
|
|
encoded_header, encoded_payload, signature = parts
|
|
expected_signature = sign("#{encoded_header}.#{encoded_payload}")
|
|
|
|
raise AuthenticationError, "Invalid token signature" unless signature == expected_signature
|
|
|
|
payload_bytes = base64_url_decode(encoded_payload)
|
|
raise AuthenticationError, "Failed to decode payload" unless payload_bytes
|
|
|
|
payload = JSON.parse(payload_bytes)
|
|
|
|
if payload["exp"] && payload["exp"] < Time.now.to_i
|
|
raise AuthenticationError, "Token has expired"
|
|
end
|
|
|
|
payload
|
|
end
|
|
|
|
# Clear the cached JWT token
|
|
def clear_token_cache
|
|
@token_cache = nil
|
|
@token_expiry = nil
|
|
end
|
|
|
|
private
|
|
|
|
def token_valid?
|
|
@token_cache && @token_expiry && Time.now.to_i < @token_expiry
|
|
end
|
|
|
|
def base64_url_encode(data)
|
|
json = data.to_json
|
|
Base64.urlsafe_encode64(json).gsub("=", "")
|
|
end
|
|
|
|
def base64_url_decode(data)
|
|
# Add padding if needed
|
|
padded_data = data + "=" * (4 - data.length % 4)
|
|
Base64.urlsafe_decode64(padded_data)
|
|
end
|
|
|
|
def sign(data)
|
|
hmac = OpenSSL::HMAC.new(@jwt_secret, OpenSSL::Digest::SHA256.new)
|
|
hmac.update(data)
|
|
Base64.urlsafe_encode64(hmac.digest).gsub("=", "")
|
|
end
|
|
end
|
|
end
|