kevinschweikert

kevinschweikert

Hi there,

is there a recommended way to encrypt/decrypt fields of a resource to the database?

I’ve used Cloak before, but i struggle to understand, how this would integrate into Ash.
It would be really nice if it worked like Cloak and with that I mean, that it encrypts/decrypts the data automatically when inserting/reading.

Showing Posts 1 to 7

zachdaniel

zachdaniel

Creator of Ash

In AshHq we use cloak to encrypt data. We do it with a combination of changes and calculations.

For instance:

attribute :encrypted_name, :string
attribute :encrypted_address, :string

Then, in actions we write to those attributes using arguments:

    update :update_merch_settings do
      argument :address, :string
      argument :name, :string

      accept [:shirt_size]
      change set_attribute(:encrypted_address, arg(:address))
      change set_attribute(:encrypted_name, arg(:name))
    end
  end

We don’t write to the encrypted attributes directly to prevent double encryption.

This is what our encryption change looks like:

defmodule AshHq.Changes.Encrypt do
  @moduledoc "Encrypt attributes that are being changed before submitting the action"
  use Ash.Resource.Change

  def change(changeset, opts, _) do
    Ash.Changeset.before_action(changeset, fn changeset ->
      Enum.reduce(opts[:fields], changeset, fn field, changeset ->
        case Ash.Changeset.fetch_change(changeset, field) do
          {:ok, value} when is_binary(value) ->
            new_value =
              value
              |> AshHq.Vault.encrypt!()
              |> Base.encode64()

            Ash.Changeset.force_change_attribute(changeset, field, new_value)

          _ ->
            changeset
        end
      end)
    end)
  end
end

And we apply it on every action like so:

  changes do
    ...
    change {AshHq.Changes.Encrypt, fields: [:encrypted_address, :encrypted_name]}
  end

Then, we can decrypt it on demand using calculations:

  calculations do
    calculate :address, :string, {Decrypt, field: :encrypted_address}
    calculate :name, :string, {Decrypt, field: :encrypted_name}
  end

And that calculation looks like this:

defmodule AshHq.Calculations.Decrypt do
  @moduledoc "Decrypts a given value on demand"
  use Ash.Calculation

  @impl Ash.Calculation
  def calculate(records, opts, _) do
    {:ok,
     Enum.map(records, fn record ->
       record
       |> Map.get(opts[:field])
       |> case do
         nil ->
           nil

         value ->
           value
           |> Base.decode64!()
           |> AshHq.Vault.decrypt!()
       end
     end)}
  end

  @impl Ash.Calculation
  def load(_, opts, _) do
    [opts[:field]]
  end
end

This was a very early addition to AshHq. I’d love to see an encryption extension at some point :slight_smile:

zachdaniel

zachdaniel

Creator of Ash

We initially implemented this as an Ash.Type, but it actually gets a bit strange further down the line. You can’t cast_input the value that you get back from cast_input and so you have to be careful not to accidentally double encrypt things. This way keeps things very clean.

jimsynz

jimsynz

Ash Core Team

We also use this calculation based approach in a client app and it’s very handy because you have to explicitly ask for the decrypted value (via a load) and due to our policy configuration you have to provide an actor which also gives us a place to add audit logging at a later date.

kevinschweikert

kevinschweikert OP

Thank you @zachdaniel! That worked like a charm! I slowly begin to understand how Ash works :slight_smile:

mudspot

mudspot

@zachdaniel Hi! Is this still the recommended way of doing this in 2025?

I now have the following actions definition. I am hoping for something like that in the read action

create :create do
  accept [....]
  change EncryptValue
end

read :read do
  before_action DecryptValue
end

Is something like before_action possible in the read action to handle the decryption?
Of course, I’m using calculations at the moment.

zachdaniel

zachdaniel

Creator of Ash

Take a look at AshCloak: Home — ash_cloak v0.3.1

mudspot

mudspot

Brilliant!

I managed to implement it with my custom Vault (without Cloak)

Thank you!

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews