Class: Kilden::IdentitySigner
- Inherits:
-
Object
- Object
- Kilden::IdentitySigner
- Defined in:
- lib/kilden/identity_signer.rb
Overview
Signs the short-lived identity tokens that make browser events verifiable (Kilden's trust model). Deliberately separate from Client: a controller rendering a page wants a token, not an event queue.
signer = Kilden::IdentitySigner.new(ENV["KILDEN_IDENTITY_SECRET"], kid: "k1")
token = signer.sign(current_user.id.to_s, traits: { plan: "pro" })
Only sign a sub your backend authenticated. Signing user input
(params) lets anyone impersonate anyone — with a "verified"
stamp on top.
HS256 is implemented by hand because the spec freezes the byte form of the token (kilden-sdk-spec §6.1); a JWT library's serialization choices would silently diverge.
Constant Summary collapse
- MAX_TTL =
7 days; identity tokens are short-lived by design
604_800
Instance Method Summary collapse
-
#initialize(identity_secret, kid:) ⇒ IdentitySigner
constructor
A new instance of IdentitySigner.
-
#sign(sub, ttl: 3600, traits: nil) ⇒ Object
Returns the signed JWT for
sub(the distinct_id the token vouches for).
Constructor Details
#initialize(identity_secret, kid:) ⇒ IdentitySigner
Returns a new instance of IdentitySigner.
23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/kilden/identity_signer.rb', line 23 def initialize(identity_secret, kid:) if !identity_secret.is_a?(String) || identity_secret.empty? raise ConfigurationError, "identity secret is required" end if !kid.is_a?(String) || kid.empty? raise ConfigurationError, "kid is required (the platform looks the secret up by kid)" end @secret = identity_secret @kid = kid end |
Instance Method Details
#sign(sub, ttl: 3600, traits: nil) ⇒ Object
Returns the signed JWT for sub (the distinct_id the token vouches
for). ttl defaults to one hour and is capped at 7 days.
39 40 41 42 43 44 45 |
# File 'lib/kilden/identity_signer.rb', line 39 def sign(sub, ttl: 3600, traits: nil) raise ArgumentError, "sub must be a non-empty string" if !sub.is_a?(String) || sub.empty? raise ArgumentError, "ttl must be in (0, #{MAX_TTL}] seconds" if !ttl.is_a?(Integer) || ttl <= 0 || ttl > MAX_TTL iat = Time.now.to_i build(sub, iat: iat, exp: iat + ttl, traits: traits) end |