Lightning.Credentials (Lightning v2.14.13-pre1)
View SourceThe Credentials context.
Summary
Functions
Retrieves basic auth strings for a credential in a specific environment.
Extracts basic auth strings from a credential body map.
Returns an %Ecto.Changeset{} for tracking credential changes.
Returns an %Ecto.Changeset{} for tracking keychain credential changes.
Confirms and executes a credential transfer.
Creates a new credential with its credential bodies.
Creates a keychain credential.
Returns an empty changeset structure for credential transfers with an email field.
Creates a changeset for transferring credentials, validating the provided email.
Deletes a credential.
Deletes a keychain credential.
Gets a single credential.
Gets a credential body for a specific environment.
Gets a single keychain credential.
Creates a credential schema from credential json schema.
Checks if a given Credential has any associated Step activity.
Initiates a credential transfer from the owner to the receiver.
Retrieves all credentials based on the given context, either a Project or a User.
Returns the list of keychain credentials for a project.
Returns all credentials owned by a specific user that are also being used in a specific project.
Creates a new keychain credential struct with proper associations.
Normalizes OAuth token expiry time to always use expires_at.
Checks if an OAuth token body is expired or expires soon.
Perform, when called with %{"type" => "purge_deleted"} will find credentials that are ready for permanent deletion, set their bodies to null, and try to purge them.
Gets a credential body for an environment and refreshes OAuth tokens if expired.
Revokes a pending credential transfer.
Schedules a given credential for deletion.
Retrieves sensitive values for a credential in a specific environment.
Extracts sensitive values from a credential body map.
Updates an existing credential and its credential bodies.
Updates a keychain credential.
Validates a credential transfer request.
Types
Functions
@spec basic_auth_for(Lightning.Credentials.Credential.t() | nil, String.t()) :: [ String.t() ]
Retrieves basic auth strings for a credential in a specific environment.
Used primarily for scrubbing historical dataclips where we need to look up the credential body by environment.
Parameters
credential: Credential struct or nilenvironment: Environment name (defaults to "main")
Examples
iex> basic_auth_for(credential, "staging")
["dXNlcjpwYXNz"]
Extracts basic auth strings from a credential body map.
Examples
iex> basic_auth_from_body(%{"username" => "user", "password" => "pass"})
["dXNlcjpwYXNz"]
Returns an %Ecto.Changeset{} for tracking credential changes.
Examples
iex> change_credential(credential)
%Ecto.Changeset{data: %Credential{}}
Returns an %Ecto.Changeset{} for tracking keychain credential changes.
Examples
iex> change_keychain_credential(keychain_credential)
%Ecto.Changeset{data: %KeychainCredential{}}
@spec confirm_transfer(String.t(), String.t(), String.t(), String.t()) :: {:ok, Lightning.Credentials.Credential.t()} | {:error, transfer_error() | Ecto.Changeset.t()}
Confirms and executes a credential transfer.
This function:
- Verifies the transfer token to ensure the request is valid.
- Transfers the credential from the
ownerto thereceiver. - Records the transfer in the audit log.
- Deletes all related credential transfer tokens.
- Notifies both parties about the transfer.
Parameters
credential_id: The ID of theCredentialbeing transferred.receiver_id: The ID of theUserreceiving the credential.owner_id: The ID of theUsercurrently owning the credential.token: The transfer token for verification.
Returns
{:ok, credential}on successful transfer.{:error, reason}if the transfer fails.
Errors
{:error, :not_found}if the credential or receiver does not exist.{:error, :token_error}if the token is invalid.{:error, :not_owner}if the token does not match the credential owner.{:error, changeset}if there is a validation or update issue.
Example
case confirm_transfer(credential_id, receiver_id, owner_id, token) do
{:ok, credential} -> IO.puts("Transfer successful")
{:error, :not_found} -> IO.puts("Error: Credential or receiver not found")
{:error, :token_error} -> IO.puts("Error: Invalid transfer token")
{:error, reason} -> IO.inspect(reason, label: "Transfer failed")
end
@spec create_credential(map()) :: {:ok, Lightning.Credentials.Credential.t()} | {:error, any()}
Creates a new credential with its credential bodies.
Parameters
attrs- Map of attributes for the credential including:user_id- User ID (required)name- Credential name (required)schema- Schema type (e.g., "oauth", "raw", etc.)oauth_client_id- OAuth client ID (for OAuth credentials)credential_bodies- List of credential body maps, each containing:name- Environment name (e.g., "production", "staging")body- Credential configuration data
expected_scopes- List of expected scopes (for OAuth credentials)
Returns
{:ok, credential}- Successfully created credential{:error, error}- Error with creation process
Creates a keychain credential.
Examples
iex> create_keychain_credential(%{name: "My Keychain", path: "$.user_id"})
{:ok, %KeychainCredential{}}
iex> create_keychain_credential(%{name: nil})
{:error, %Ecto.Changeset{}}
@spec credential_transfer_changeset() :: Ecto.Changeset.t()
Returns an empty changeset structure for credential transfers with an email field.
Returns
An Ecto.Changeset struct with an empty data map and an email field.
Example
iex> credential_transfer_changeset()
#Ecto.Changeset<...>
@spec credential_transfer_changeset(String.t()) :: Ecto.Changeset.t()
Creates a changeset for transferring credentials, validating the provided email.
Parameters
email: The email address to be included in the changeset.
Returns
An Ecto.Changeset containing the email field.
Example
iex> credential_transfer_changeset("user@example.com")
#Ecto.Changeset<...>
Deletes a credential.
Examples
iex> delete_credential(credential)
{:ok, %Credential{}}
iex> delete_credential(credential)
{:error, %Ecto.Changeset{}}
Deletes a keychain credential.
Examples
iex> delete_keychain_credential(keychain_credential)
{:ok, %KeychainCredential{}}
iex> delete_keychain_credential(keychain_credential)
{:error, %Ecto.Changeset{}}
Gets a single credential.
Raises Ecto.NoResultsError if the Credential does not exist.
Examples
iex> get_credential!(123)
%Credential{}
iex> get_credential!(456)
** (Ecto.NoResultsError)
@spec get_credential_body(String.t(), String.t()) :: Lightning.Credentials.CredentialBody.t() | nil
Gets a credential body for a specific environment.
Returns nil if no body exists for the given credential and environment combination.
Examples
iex> get_credential_body(credential_id, "production")
%CredentialBody{name: "production", body: %{...}}
iex> get_credential_body(credential_id, "nonexistent")
nil
Gets a single keychain credential.
Raises Ecto.NoResultsError if the KeychainCredential does not exist.
Examples
iex> get_keychain_credential(123)
%KeychainCredential{}
iex> get_keychain_credential(456)
** (Ecto.NoResultsError)
@spec get_schema(String.t()) :: Lightning.Credentials.Schema.t()
Creates a credential schema from credential json schema.
Checks if a given Credential has any associated Step activity.
Parameters
_credential: ACredentialstruct. Only theidfield is used by the function.
Returns
trueif there's at least oneStepassociated with the givenCredential.falseotherwise.
Examples
iex> has_activity_in_projects?(%Credential{id: some_id})
true
iex> has_activity_in_projects?(%Credential{id: another_id})
falseNotes
This function leverages the association between Step and Credential to
determine if any steps exist for a given credential. It's a fast check that
does not load any records into memory, but simply checks for their existence.
@spec initiate_credential_transfer( Lightning.Accounts.User.t(), Lightning.Accounts.User.t(), Lightning.Credentials.Credential.t() ) :: :ok | {:error, transfer_error() | Ecto.Changeset.t()}
Initiates a credential transfer from the owner to the receiver.
This function:
- Marks the credential as
pendingfor transfer. - Generates an email token for the credential transfer.
- Sends a transfer confirmation email to the receiver.
Parameters
owner: TheUserwho currently owns the credential.receiver: TheUserwho will receive the credential.credential: TheCredentialto be transferred.
Returns
:okif the transfer process is successfully initiated.{:error, reason}if any validation or transaction step fails.
Example
case initiate_credential_transfer(owner, receiver, credential) do
:ok -> IO.puts("Transfer initiated successfully")
{:error, error} -> IO.inspect(error, label: "Transfer failed")
end
@spec list_credentials(Lightning.Projects.Project.t()) :: [ Lightning.Credentials.Credential.t() ]
@spec list_credentials(Lightning.Accounts.User.t()) :: [ Lightning.Credentials.Credential.t() ]
Retrieves all credentials based on the given context, either a Project or a User.
Parameters
- context: The Project or User struct to retrieve credentials for.
Returns
- A list of credentials associated with the given Project or created by the given User.
Examples
When given a Project:
iex> list_credentials(%Project{id: 1})
[%Credential{project_id: 1}, %Credential{project_id: 1}]When given a User:
iex> list_credentials(%User{id: 123})
[%Credential{user_id: 123}, %Credential{user_id: 123}]
Returns the list of keychain credentials for a project.
Examples
iex> list_keychain_credentials_for_project(%Project{id: 123})
[%KeychainCredential{}, ...]
@spec list_user_credentials_in_project( Lightning.Accounts.User.t(), Lightning.Projects.Project.t() ) :: [ Lightning.Credentials.Credential.t() ]
Returns all credentials owned by a specific user that are also being used in a specific project.
Parameters
user: TheUserstruct whose credentials we want to find.project: TheProjectstruct to check for credential usage.
Returns
- A list of
Credentialstructs that are owned by the user and used in the project.
Examples
iex> list_user_credentials_in_project(%User{id: 123}, %Project{id: 456})
[%Credential{user_id: 123, ...}, %Credential{user_id: 123, ...}]
Creates a new keychain credential struct with proper associations.
This function ensures that the created_by and project associations are properly set and cannot be tampered with via browser params.
Examples
iex> new_keychain_credential(user, project)
%KeychainCredential{created_by: user, project: project}
Normalizes OAuth token expiry time to always use expires_at.
Converts relative expires_in to absolute expires_at timestamp based on current time. If the token already has expires_at, returns it unchanged.
Examples
iex> normalize_token_expiry(%{"expires_in" => 3600})
%{"expires_in" => 3600, "expires_at" => 1234567890}
iex> normalize_token_expiry(%{"expires_at" => 1234567890})
%{"expires_at" => 1234567890}
Checks if an OAuth token body is expired or expires soon.
Returns true if the token expires within the next 5 minutes (300 seconds buffer). If expiry cannot be determined, conservatively returns true to trigger refresh.
Examples
iex> oauth_token_expired?(%{"expires_at" => future_timestamp})
false
iex> oauth_token_expired?(%{"expires_at" => soon_timestamp})
true
Perform, when called with %{"type" => "purge_deleted"} will find credentials that are ready for permanent deletion, set their bodies to null, and try to purge them.
@spec resolve_credential_body(Lightning.Credentials.Credential.t(), String.t()) :: {:ok, map()} | {:error, :environment_not_found | oauth_refresh_error()}
Gets a credential body for an environment and refreshes OAuth tokens if expired.
This is the primary function for credential resolution during workflow execution. It handles the full flow: fetch body → check expiration → refresh if needed → return final body.
Parameters
credential: The credential structenvironment: Environment name (e.g., "production", "staging")
Returns
{:ok, body}- The credential body (with fresh tokens if OAuth was refreshed){:error, :environment_not_found}- No body exists for this environment{:error, oauth_refresh_error()}- OAuth refresh failed
@spec revoke_transfer(String.t(), Lightning.Accounts.User.t()) :: {:ok, Lightning.Credentials.Credential.t()} | {:error, transfer_error() | Ecto.Changeset.t()}
Revokes a pending credential transfer.
This function:
- Ensures the credential exists.
- Checks that the
owneris the one who initiated the transfer. - Confirms that the credential is still in a
pendingstate. - Resets the transfer status and deletes related credential transfer tokens.
Parameters
credential_id: The ID of theCredentialbeing revoked.owner: TheUserwho owns the credential and is revoking the transfer.
Returns
{:ok, credential}if the transfer is successfully revoked.{:error, :not_found}if the credential does not exist.{:error, :not_owner}if the user does not own the credential.{:error, :not_pending}if the transfer is not in a pending state.{:error, changeset}if there is a validation or update issue.
Example
case revoke_transfer(credential_id, owner) do
{:ok, credential} -> IO.puts("Transfer revoked for credential")
{:error, :not_found} -> IO.puts("Error: Credential not found")
{:error, :not_owner} -> IO.puts("Error: You do not own this credential")
{:error, :not_pending} -> IO.puts("Error: Transfer is not pending")
{:error, reason} -> IO.inspect(reason, label: "Revoke failed")
end
Schedules a given credential for deletion.
The deletion date is determined based on the :purge_deleted_after_days configuration
in the application environment. If this configuration is absent, the credential is scheduled
for immediate deletion.
The function will also perform necessary side effects such as:
- Removing associations of the credential.
- Revoking OAuth tokens if the credential is an OAuth credential.
- Notifying the owner of the credential about the scheduled deletion.
Parameters
credential: ACredentialstruct that is to be scheduled for deletion.
Returns
{:ok, credential}: Returns an:oktuple with the updated credential struct if the update was successful.{:error, changeset}: Returns an:errortuple with the changeset if the update failed.
Examples
iex> schedule_credential_deletion(%Credential{id: some_id})
{:ok, %Credential{}}
iex> schedule_credential_deletion(%Credential{})
{:error, %Ecto.Changeset{}}
@spec sensitive_values_for( Ecto.UUID.t() | Lightning.Credentials.Credential.t() | nil, String.t() ) :: [ any() ]
Retrieves sensitive values for a credential in a specific environment.
Used primarily for scrubbing historical dataclips where we need to look up the credential body by environment.
Parameters
id_or_credential: Credential ID, Credential struct, or nilenvironment: Environment name (defaults to "main")
Examples
iex> sensitive_values_for(credential, "production")
["secret123", "api_key_xyz"]
Extracts sensitive values from a credential body map.
Examples
iex> sensitive_values_from_body(%{"password" => "secret123"})
["secret123"]
@spec update_credential(Lightning.Credentials.Credential.t(), map()) :: {:ok, Lightning.Credentials.Credential.t()} | {:error, any()}
Updates an existing credential and its credential bodies.
Parameters
credential- The credential to updateattrs- Map of attributes to update, including:credential_bodies- List of credential body maps to create/update
Returns
{:ok, credential}- Successfully updated credential{:error, error}- Error with update process
Updates a keychain credential.
Examples
iex> update_keychain_credential(keychain_credential, %{name: "Updated"})
{:ok, %KeychainCredential{}}
iex> update_keychain_credential(keychain_credential, %{name: nil})
{:error, %Ecto.Changeset{}}
@spec validate_credential_transfer( Ecto.Changeset.t(), Lightning.Accounts.User.t(), Lightning.Credentials.Credential.t() ) :: Ecto.Changeset.t()
Validates a credential transfer request.
This function ensures:
- The email format is correct.
- The email does not already exist in the system.
- The credential is not transferred to the same user.
- The recipient has access to the necessary projects.
If the changeset is valid, additional validation checks are applied.
Parameters
changeset: TheEcto.Changesetcontaining the credential transfer details.current_user: The user attempting the credential transfer.credential: The credential being transferred.
Returns
- An updated
Ecto.Changesetwith validation errors if any issues are found.