RSA keys for LTI tool authentication.
Every LTI Advantage service call requires a signed JWT assertion, and platforms verify it with the public keys your tool publishes. A JWK has a key ID and a public key, and a private key when it was made from one.
Generating a key
jwk = Ltix.JWK.generate()Store kid, public_key_pem, and private_key_pem, and encrypt the
private key.
Signing
Load the private key and sign in your storage adapter's
Ltix.StorageAdapter.sign/4 callback.
{:ok, jwk} = Ltix.JWK.new(private_key_pem: pem, kid: kid)
Ltix.JWK.sign(jwk, message)Serving your key set endpoint
Load the public keys and return them with to_jwks/1. The endpoint needs
no private key.
def jwks(conn, _params) do
json(conn, Ltix.JWK.to_jwks(MyApp.Lti.list_public_jwks()))
endHere list_public_jwks/0 builds each JWK from what you stored.
Ltix.JWK.new!(public_key_pem: pem, kid: kid)During a rotation, include the new key and the old one so platforms can verify with either.
For a key in a key management service, build the JWK from the public key the service returns, as a PEM, a DER binary, or a JWK map.
Summary
Functions
Generate an RSA key pair for LTI tool authentication.
Construct a JWK from existing key material.
Same as new/1, but returns the JWK or raises the error.
Sign a message with RS256, as Ltix.StorageAdapter.sign/4 requires.
Build a JWKS (JSON Web Key Set) map from one or more JWKs.
Export the public key as a PEM string.
Types
Functions
Generate an RSA key pair for LTI tool authentication.
Returns a %Ltix.JWK{} struct. Persist kid and the key PEMs to build
the JWK again with new/1.
Examples
jwk = Ltix.JWK.generate()
jwk = Ltix.JWK.generate(key_size: 4096)Options
:key_size(integer/0) - RSA key size in bits (minimum 2048). The default can be overridden by settingconfig :ltix, :default_key_size.
@spec new(keyword() | map()) :: {:ok, t()} | {:error, Exception.t()}
Construct a JWK from existing key material.
Takes a keyword list or an atom-keyed map with :kid and one key. Unknown
fields are rejected. A JWK made from a public key has no private key, so
it can't sign.
Fields
:kid- the key ID. Optional with:public_jwkor:private_jwkwhen the map has a"kid", which a:kidgiven with it has to match.:public_key_pem- an RSA public key as a PEM string:public_key_der- an RSA public key as a DER binary:public_jwk- an RSA public key as a string-keyed JWK map:private_key_pem- an RSA private key as an unencrypted PEM string:private_key_der- an RSA private key as a DER binary:private_jwk- an RSA private key as a string-keyed JWK map
Examples
{:ok, jwk} = Ltix.JWK.new(private_key_pem: pem, kid: "my-key-id")
{:ok, jwk} = Ltix.JWK.new(public_key_pem: public_pem, kid: "my-key-id")
Same as new/1, but returns the JWK or raises the error.
Examples
jwk = Ltix.JWK.new!(private_key_pem: pem, kid: "my-key-id")
@spec sign(t(), binary()) :: {:ok, binary()} | {:error, Exception.t()}
Sign a message with RS256, as Ltix.StorageAdapter.sign/4 requires.
Returns an error for a JWK without a private key.
Examples
iex> jwk = Ltix.JWK.generate(key_size: 2048)
iex> {:ok, signature} = Ltix.JWK.sign(jwk, "message")
iex> byte_size(signature)
256
Build a JWKS (JSON Web Key Set) map from one or more JWKs.
The map has only public keys, so it is safe for public endpoints.
Accepts a single %Ltix.JWK{} or a list.
Examples
def jwks(conn, _params) do
json(conn, Ltix.JWK.to_jwks(MyApp.Lti.list_public_jwks()))
end
Export the public key as a PEM string.
Useful for manual key exchange during platform registration setup.
Examples
jwk = Ltix.JWK.generate()
public_pem = Ltix.JWK.to_public_key(jwk)