Changes profile import endpoint to use standard API token authentication: API Token Changes: - Add user_id to api_tokens table (tracks who created the token) - Update ApiTokens.verify_token/1 to return user along with org_id - Update ApiAuth plug to assign current_user from token Profile Import Changes: - Move endpoint from /api/v1/admin/profiles/import to /api/v1/profiles/import - Check user.is_superuser in controller instead of using RequireSuperuser plug - Use api_v1 pipeline (Bearer token auth) instead of browser session - Update documentation to show API token usage Security: - Only API tokens created by superusers can import profiles - Returns 403 Forbidden if token user is not a superuser - Logs import attempts with user email for audit trail This provides a consistent API experience using Bearer tokens instead of requiring browser session cookies.
40 lines
1.2 KiB
Elixir
40 lines
1.2 KiB
Elixir
defmodule Towerops.ApiTokens.ApiToken do
|
|
@moduledoc """
|
|
Schema for API tokens scoped to organizations.
|
|
|
|
API tokens allow programmatic access to the Towerops API for managing
|
|
sites, devices, and other resources within an organization.
|
|
|
|
The actual token value is only shown once when created and is then
|
|
hashed for secure storage.
|
|
"""
|
|
use Ecto.Schema
|
|
|
|
import Ecto.Changeset
|
|
|
|
@primary_key {:id, :binary_id, autogenerate: true}
|
|
@foreign_key_type :binary_id
|
|
|
|
schema "api_tokens" do
|
|
field :name, :string
|
|
field :token_hash, :string
|
|
field :last_used_at, :utc_datetime
|
|
field :expires_at, :utc_datetime
|
|
|
|
belongs_to :organization, Towerops.Organizations.Organization
|
|
belongs_to :user, Towerops.Accounts.User
|
|
|
|
timestamps(type: :utc_datetime)
|
|
end
|
|
|
|
@doc false
|
|
def changeset(api_token, attrs) do
|
|
api_token
|
|
|> cast(attrs, [:organization_id, :user_id, :name, :token_hash, :expires_at, :last_used_at])
|
|
|> validate_required([:organization_id, :name, :token_hash])
|
|
|> validate_length(:name, min: 1, max: 255)
|
|
|> unique_constraint(:token_hash)
|
|
|> foreign_key_constraint(:organization_id)
|
|
|> foreign_key_constraint(:user_id)
|
|
end
|
|
end
|