View Source AppIdentity (AppIdentity for Elixir v1.1.0)

AppIdentity is an Elixir implementation of the Kinetic Commerce application identity proof algorithm.

It implements identity proof generation and validation functions. These functions expect to work with an application structure (AppIdentity.App.t/0).

telemetry-support

Telemetry Support

If telemetry is a dependency in your application, and the telemetry is not explicitly disabled, telemetry events will be emitted for AppIdentity.generate_proof/2, AppIdentity.verify_proof/3, and AppIdentity.Plug. See AppIdentity.Telemetry for more information.

disabling-telemetry

Disabling Telemetry

Telemetry may be disabled by setting this for your configuration:

config :app_identity, AppIdentity.Telemetry, enabled: false

Remember to run mix deps.compile --force tesla after changing this setting to ensure the change is picked up.

Link to this section Summary

Types

A list of algorithm versions that are not allowed.

The App Identity app unique identifier. Validation of the id value will convert non-string IDs using Kernel.to_string/1.

A nonce value used in the algorithm proof. The shape of the nonce depends on the algorithm version/0.

Options for generating or verifying proofs.

The App Identity app secret value. This value is used as provided with no encoding or decoding. Because this is a sensitive value, it may be provided as a closure in line with the EEF Security Working Group sensitive data recommendation.

The positive integer version of the App Identity algorithm to use. Will be validated to be a supported version for app creation, and not an explicitly disallowed version during proof validation.

Functions

Generate an identity proof string for the given application. Returns {:ok, proof} or :error.

Generate an identity proof string for the given application. Returns the proof string or raises an exception on error.

The name, version, and supported specification version of this App Identity package for Elixir.

The name, version, or supported specification version of this App Identity package for Elixir.

Parses a proof string into an AppIdentity.Proof struct. Returns {:ok, proof} or :error.

Parses a proof string into an AppIdentity.Proof struct. Returns the parsed proof or raises an exception.

Verify a AppIdentity proof value using a a provided app. Returns {:ok, app}, {:ok, nil}, or :error.

Verify a AppIdentity proof value using a a provided app. Returns the app, nil, or raises an exception on error.

Link to this section Types

@type disallowed() :: {:disallowed, [version()]}

A list of algorithm versions that are not allowed.

The presence of an app in this list will prevent the generation or verification of proofs for the specified version.

If nil, an empty list, or missing, all versions are allowed.

@type id() :: binary()

The App Identity app unique identifier. Validation of the id value will convert non-string IDs using Kernel.to_string/1.

If using integer IDs, it is recommended that the id value be provided as some form of extended string value, such as that provided by Rails global ID or the absinthe_relay Node.IDTranslator. Such representations are also recommended if the ID is a compound value.

id/0 values must not contain a colon (:) character.

@type nonce() :: String.t()

A nonce value used in the algorithm proof. The shape of the nonce depends on the algorithm version/0.

Version 1 nonce/0 values should be cryptographically secure and non-sequential, but sufficiently fine-grained timestamps (those including microseconds, as yyyymmddHHMMSS.sss) may be used. Version 1 proofs verify that the nonce is at least one byte long and do not contain a colon (:).

Version 2, 3, and 4 nonce/0 values only permit fine-grained timestamps that should be generated from a clock in sync with Network Time Protocol servers. The timestamp will be parsed and compared to the server time (also in sync with an NTP server).

@type option() :: disallowed() | {:nonce, nonce()} | {:version, version()}

Options for generating or verifying proofs.

  • nonce can specify a precomputed nonce for proof generation. It will be verified by the algorithm version for correctness and compatibility, but will otherwise be used unmodified. This option is ignored for proof verification.

  • version can specify the generation of a proof compatible with, but different than, the application version. This option is ignored for proof verification.

@type secret() :: binary()

The App Identity app secret value. This value is used as provided with no encoding or decoding. Because this is a sensitive value, it may be provided as a closure in line with the EEF Security Working Group sensitive data recommendation.

AppIdentity.App always stores this value as a closure.

@type version() :: pos_integer()

The positive integer version of the App Identity algorithm to use. Will be validated to be a supported version for app creation, and not an explicitly disallowed version during proof validation.

If provided as a string value, it must convert cleanly to an integer value, which means that a version of "3.5" is not a valid value.

App Identity algorithm versions are strictly upgradeable. That is, a version 1 app can verify version 1, 2, 3, or 4 proofs. However, a version 2 app will never validate a version 1 proof.

Version Nonce Digest Algorithm Can Verify
1234
1randomSHA 256
2timestamp ± fuzzSHA 256⛔️
3timestamp ± fuzzSHA 384⛔️⛔️
4timestamp ± fuzzSHA 512⛔️⛔️⛔️

Link to this section Functions

Link to this function

generate_proof(app, options \\ [])

View Source
@spec generate_proof(
  AppIdentity.App.t() | AppIdentity.App.loader() | AppIdentity.App.t(),
  [option()]
) ::
  {:ok, String.t()} | :error

Generate an identity proof string for the given application. Returns {:ok, proof} or :error.

If nonce is provided, it must conform to the shape expected by the proof version. If not provided, it will be generated.

If version is provided, it will be used to generate the nonce and the proof. This will allow a lower level application to raise its version level.

examples

Examples

A version 1 app can have a fixed nonce, which will always produce the same value.

iex> {:ok, app} = AppIdentity.App.new(%{version: 1, id: "decaf", secret: "bad"})
iex> AppIdentity.generate_proof(app, nonce: "hello")
{:ok, "ZGVjYWY6aGVsbG86RDNGNjJCQTYyOEIyMzhEOTgwM0MyNEU4NkNCOTY3M0ZEOTVCNTdBNkJGOTRFMkQ2NTMxQTRBODg1OTlCMzgzNQ=="}

A version 2 app fails when given a non-timestamp nonce.

iex> AppIdentity.generate_proof(v1(), version: 2, nonce: "hello")
:error

A version 2 app cannot generate a version 1 nonce.

iex> AppIdentity.generate_proof(v2(), version: 1)
:error

A version 2 app will be rejected if the version has been disallowed.

iex> AppIdentity.generate_proof(v2(), disallowed: [1, 2])
:error

telemetry

Telemetry

When telemetry is enabled, generate_proof/2 will emit:

  • [:app_identity, :generate_proof, :start]
  • [:app_identity, :generate_proof, :stop]
Link to this function

generate_proof!(app, options \\ [])

View Source
@spec generate_proof!(
  AppIdentity.App.t() | AppIdentity.App.loader() | AppIdentity.App.t(),
  [option()]
) ::
  String.t()

Generate an identity proof string for the given application. Returns the proof string or raises an exception on error.

If nonce is provided, it must conform to the shape expected by the proof version. If not provided, it will be generated.

If version is provided, it will be used to generate the nonce and the proof. This will allow a lower level application to raise its version level.

examples

Examples

A version 1 app can have a fixed nonce, which will always produce the same value.

iex> {:ok, app} = AppIdentity.App.new(%{version: 1, id: "decaf", secret: "bad"})
iex> AppIdentity.generate_proof!(app, nonce: "hello")
"ZGVjYWY6aGVsbG86RDNGNjJCQTYyOEIyMzhEOTgwM0MyNEU4NkNCOTY3M0ZEOTVCNTdBNkJGOTRFMkQ2NTMxQTRBODg1OTlCMzgzNQ=="

A version 2 app fails when given a non-timestamp nonce.

iex> AppIdentity.generate_proof!(v1(), version: 2, nonce: "hello")
** (AppIdentity.AppIdentityError) Error generating proof

A version 2 app cannot generate a version 1 nonce.

iex> AppIdentity.generate_proof!(v2(), version: 1)
** (AppIdentity.AppIdentityError) Error generating proof

A version 2 app will be rejected if the version has been disallowed.

iex> AppIdentity.generate_proof!(v2(), disallowed: [1, 2])
** (AppIdentity.AppIdentityError) Error generating proof

telemetry

Telemetry

When telemetry is enabled, generate_proof!/2 will emit:

  • [:app_identity, :generate_proof, :start] -[:app_identity, :generate_proof, :stop]` Telemetry events are emitted before any error exceptions are thrown.
@spec info() :: %{name: String.t(), version: String.t(), spec_version: pos_integer()}

The name, version, and supported specification version of this App Identity package for Elixir.

@spec info(:name | :spec_version | :version) :: String.t() | pos_integer()

The name, version, or supported specification version of this App Identity package for Elixir.

@spec parse_proof(AppIdentity.Proof.t() | String.t()) ::
  {:ok, AppIdentity.Proof.t()} | :error

Parses a proof string into an AppIdentity.Proof struct. Returns {:ok, proof} or :error.

@spec parse_proof!(AppIdentity.Proof.t() | String.t()) :: AppIdentity.Proof.t()

Parses a proof string into an AppIdentity.Proof struct. Returns the parsed proof or raises an exception.

Link to this function

verify_proof(proof, app, options \\ [])

View Source
@spec verify_proof(
  AppIdentity.Proof.t() | String.t(),
  AppIdentity.App.finder() | AppIdentity.App.input() | AppIdentity.App.t(),
  [option()]
) :: {:ok, AppIdentity.App.t() | nil} | :error

Verify a AppIdentity proof value using a a provided app. Returns {:ok, app}, {:ok, nil}, or :error.

The proof may be provided either as a string or a parsed AppIdentity.Proof.t/0 (from parse_proof/1). String proof values are usually obtained from HTTP headers. At Kinetic Commerce, this has generally jeen KCS-Application or KCS-Service.

The app can be provided as one of AppIdentity.App.input/0, AppIdentity.App.t/0, or AppIdentity.App.finder/0. If provided a finder, it will be called with the proof value.

verify_proof/3 has three possible return values:

  • {:ok, AppIdentity.App} when the proof is validated against the provided or located application;
  • {:ok, nil} when the proof matches the provided or located application, but it does not validate.
  • :error when there is any error during proof validation.
AppIdentity.verify_proof(proof, &IdentityApplications.get!(&1.id))

telemetry

Telemetry

When telemetry is enabled, verif_proof/3 will emit:

  • [:app_identity, :verify_proof, :start]
  • [:app_identity, :verify_proof, :stop]
Link to this function

verify_proof!(proof, app, options \\ [])

View Source

Verify a AppIdentity proof value using a a provided app. Returns the app, nil, or raises an exception on error.

The proof may be provided either as a string or a parsed AppIdentity.Proof.t/0 (from parse_proof/1). String proof values are usually obtained from HTTP headers. At Kinetic Commerce, this has generally jeen KCS-Application or KCS-Service.

The app can be provided as one of AppIdentity.App.input/0, AppIdentity.App.t/0, or AppIdentity.App.finder/0. If provided a finder, it will be called with the proof value.

verify_proof/3 has two possible return values:

  • AppIdentity.App when the proof is validated against the provided or located application;
  • nil when the proof matches the provided or located application, but it does not validate.

It raises an exception on any error during proof validation.

AppIdentity.verify_proof(proof, &IdentityApplications.get!(&1.id))

telemetry

Telemetry

When telemetry is enabled, verify_proof!/3 will emit:

  • [:app_identity, :verify_proof, :start]
  • [:app_identity, :verify_proof, :stop]

Telemetry events are emitted before any error exceptions are thrown.