{"id":23497984,"url":"https://github.com/freedomben/malan","last_synced_at":"2025-04-15T15:38:48.410Z","repository":{"id":37905276,"uuid":"249869696","full_name":"FreedomBen/malan","owner":"FreedomBen","description":"An \"authentication\" service which you can add to your eco-system and use via API, or you can fork and use as the basis of a new Phoenix application","archived":false,"fork":false,"pushed_at":"2024-08-28T17:46:23.000Z","size":1057,"stargazers_count":5,"open_issues_count":14,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-28T22:01:36.561Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FreedomBen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-25T02:37:30.000Z","updated_at":"2024-08-28T17:46:22.000Z","dependencies_parsed_at":"2023-10-12T00:45:04.100Z","dependency_job_id":"c6dec955-3907-48c3-9e70-a86dae458b43","html_url":"https://github.com/FreedomBen/malan","commit_stats":null,"previous_names":[],"tags_count":51,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FreedomBen%2Fmalan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FreedomBen%2Fmalan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FreedomBen%2Fmalan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FreedomBen%2Fmalan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FreedomBen","download_url":"https://codeload.github.com/FreedomBen/malan/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249099841,"owners_count":21212736,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-25T05:17:38.213Z","updated_at":"2025-04-15T15:38:48.394Z","avatar_url":"https://github.com/FreedomBen.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Malan Authentication Service\n\nMalan is a basic authentication service that you can drop into you microservice ecosystem, or even use as a base for a new Phoenix project.\n\n## Use Malan\n\n### Basic endpoints you'll use\n\nIf using Malan as an authentication service, there are 3 main endpoints you'll use:\n\n1.  Create a user:  `POST /api/users`\n1.  Login (get an auth token) for a user:  `POST /api/sessions`\n1.  Check auth status:  `GET /api/users/whoami`\n\n### Structuring your app with Malan\n\nThere are a couple of different ways to structure your application.  One way to structure your app around Malan is to outsource your user and session model to Malan.  Malan allows you to set an arbitrary JSON blob (called `custom_attrs`) on each user, so you can pack a decent amount of info in there.  The user's API token can be stored in session storage and you can easily use just the token to retrieve the relevant user from Malan.  If the token is expired, revoked, or otherwise invalid then no user will be returned so you can trigger a new login page.\n\nAnother common option is to maintain a minimal User table in your app that contains the user's malan ID.  If you have a number of things you want to store then this may be a better approach than jamming everything into `custom_attrs`.\n\n## Run Malan\n\nIf you have a clone of this repo, you can start Malan easily using Docker Compose:\n\n```bash\ndocker-compose up\n```\n\n### Adding Malan service to an eco-system\n\nIf you are adding Malan to your current application, you can make use of [the example docker-compose file](https://github.com/FreedomBen/malan/blob/main/docker-compose-example.yml).  You will need to add Malan, and a Postgres for Malan to use as its data store.\n\n```yaml\nversion: \"3.9\"\nservices:\n  postgres:\n    image: 'docker.io/postgres:12.6-alpine'\n    volumes:\n      - 'pgdata:/var/lib/postgresql/data'  # Use a docker volume for the database files\n    environment:\n      POSTGRES_USER: 'postgres'\n      POSTGRES_PASSWORD: 'postgres'\n\n  malan:\n    image: 'docker.io/freedomben/malan-dev:latest'\n    ports:\n      - \"4000:4000\"\n    environment:\n      DB_INIT: 'Yes'\n      DB_USERNAME: 'postgres'\n      DB_PASSWORD: 'postgres'\n      DB_HOSTNAME: 'postgres'\n      BIND_ADDR: '0.0.0.0'\n    depends_on:\n      - 'postgres'\n\nvolumes:\n  pgdata:\n```\n\n### Setting up a local development environment\n\n  You'll need to:\n\n#### 1.  Install Elixir and Mix\n\nSetup instructions vary by platform.\n\nFedora, CentOS, or RHEL:\n\n```bash\ndnf install -y elixir\n```\n\nUbuntu:\n\n```bash\napt install -y elixir\n```\n\nMac OS:\n\n```bash\nbrew install elixir\n```\n\n#### 2.  Setup Hex\n\n```bash\nmix local.hex\n```\n\nIf you need to install Phoenix separately, you can do so with hex:\n\n```bash\nmix archive.install hex phx_new 1.5.8\n```\n\n#### 3.  Clone this repo and install dependencies\n\n```bash\ngit clone https://github.com/freedomben/malan.git \\\ncd malan\nmix deps.get\n```\n\n#### 4.  Run migrations\n\nNote:  You'll need Postgres to be running before completing this step.   If you are not using docker-compose, you can make use of the script at `script/start-postgres.sh` to quickly get a database running.\n\n```bash\nmix ecto.setup\n```\n\n#### 5.  Start the Phoenix server\n\n```bash\nmix phx.server\n```\n\n## Malan API\n\nThe Malan API is a pretty standard REST interface.  For details, please visit [API.md](https://github.com/FreedomBen/malan/blob/main/API.md).\n\nIf your client will be in TypeScript, you can also consider using [libmalan](https://github.com/FreedomBen/libmalan), a simple utility package that provides TypeScript methods.\n\n## CI/CD and Deployment\n\nStaging deploys automatically upon merge to main.  Prod deploys after being tagged:\n\n```bash\ngit tag \"prod-$(date '+%Y-%m-%d-%H-%M-%S')\"\ngit push --tags\n```\n\n### Configuring PostgreSQL users\n\nYou should run the web application as a non-privileged user that cannot run DDL commands, and the migrations as a privileged user who can.\n\n```SQL\nCREATE ROLE malan WITH LOGIN PASSWORD '\u003csomepassword\u003e';\nGRANT CONNECT ON DATABASE malan_prod TO user;\nGRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO malan;\n\nALTER DEFAULT PRIVILEGES FOR ROLE\n    malan\n  IN SCHEMA\n    public\n  GRANT\n    SELECT, INSERT, UPDATE, DELETE\n  ON TABLES TO\n    malan;\n```\n\n## Helpful links regarding Phoenix\n\n  * Official website: https://www.phoenixframework.org/\n  * Guides: https://hexdocs.pm/phoenix/overview.html\n  * Docs: https://hexdocs.pm/phoenix\n  * Forum: https://elixirforum.com/c/phoenix-forum\n  * Source: https://github.com/phoenixframework/phoenix\n\n\n## CI/CD\n\nThe CI/CD system utilizes Github Actions to run automated builds, tests, and deployments to all environments.\n\n### Environments\n\n#### Prod\n\nThe Production environment is where the production instances of the application are running.  Deployments to Production are fully automated but are not automatic.  Deploys to Production are triggered using git tags.\n\n#### Staging\n\nThe staging environment.  Staging is typically a small change ahead of production to allow for testing in a \"prod-like\" environment\n\nAll commits, merges, and tags added to the `main` branch will automatically trigger a deployment to staging.\n\n### The pieces to CI/CD in this repo are these\n\n1.  `.github/workflows/build-test-deploy.yaml`:  This yaml file contains the Github-specific configuration.  It tells Github Actions how to run the build, push the image, run the tests, and deploy the change.\n1.  `scripts/build-release.sh:  This script contains the instructions that build the release into an image.\n1.  `scripts/push-release.sh:  This script contains the instructions that push the application image to the registry.\n1.  `scripts/deploy-release.sh:  This script contains the instructions that deploy the change to Kubernetes.  It contains the bulk of the CD logic.\n\n## Audit Logs\n\nMany actions are logged in the audit log.  Whether the action result is success or failure, it is logged.  The data that is sent as part of the request is recorded for later analysis.\n\nHere is a (non comprehensive) list of actions logged:\n\n* Creating a user.  Includes the original creation data except password\n* Updating a user.  Includes the changed data\n* Locking a user\n* Unlocking a user\n* Deleting a user\n* Requesting a password reset token\n* Using a password reset token\n* Changing a user password\n* Creating a session (aka \"logging in\")\n* Deleting a session (aka \"logging out\")\n* Extending a session\n\nWhile there aren't (currently) any REST API endpoints for logs they can be accessed through the database, either using `iex` or using Postgres (examples shown using `psql`).\n\nNOTE:  In order to optimize the logs table for _writes_, the indexes are minimal.  This means there is a long and beefy table scan for querying.  Keep this in mind if you have a large production table!\n\n### Using psql\n\n1.  Get a shell in a running container.  If using Kubernetes, you can use `kubectl exec`.  Substitute the pod name for a current pod in your environment.  You can list them with `kubectl -n malan-staging get pods`\n\n  ```bash\n  $ kubectl -n malan-staging exec -it \u003cvalid-pod-name\u003e -- bash\n  ```\n\n2.  Start a `psql` shell.  There is a convenient alias in the bashrc already that you can use to connect to the database for that pod:\n\n  ``` bash\n  $ psql-malan\n  ```\n\n3.  Run your queries.  There are some examples in the next section:\n\n#### Postgres example queries:\n\nGet entire log history for a user with ID `ffa9c147-900b-4813-b738-9b924237fdc7` (Note this could be huge!  Use caution in production)\n\n```SQL\nSELECT *\nFROM logs\nWHERE user_id = 'ffa9c147-900b-4813-b738-9b924237fdc7'\nORDER BY logs.inserted_at DESC;\n```\n\nGet 10 most recent logs for a user with ID `ffa9c147-900b-4813-b738-9b924237fdc7`\n\n```SQL\nSELECT *\nFROM logs\nWHERE user_id = 'ffa9c147-900b-4813-b738-9b924237fdc7'\nORDER BY logs.inserted_at DESC\nLIMIT 10;\n```\n\nGet 10 most recent logs for a user with email address `hello@example.com`\n\n```SQL\nSELECT logs.*\nFROM logs\nJOIN users ON logs.user_id = users.id\nWHERE users.email = 'hello@example.com'\nORDER BY logs.inserted_at DESC\nLIMIT 10;\n```\n\nGet the 10 most recent logs for user with ID `ef886248-32b9-48c1-bd4d-303c1cda1f94` that were \"Unauthorized login attempt\":\n\n```SQL\nSELECT *\nFROM logs\nWHERE user_id = 'ef886248-32b9-48c1-bd4d-303c1cda1f94'\n  AND what LIKE '%Unauthorized%'\nORDER BY inserted_at DESC\nLIMIT 10;\n```\n\nGet the 10 most recent logs for user email `hello@example.com` that were \"Unauthorized login attempt\":\n\n```SQL\nSELECT logs.*\nFROM logs\nJOIN users ON logs.user_id = users.id\nWHERE users.email = 'hello@example.com'\n  AND logs.what LIKE '%Unauthorized%'\nORDER BY logs.inserted_at DESC\nLIMIT 10;\n```\n\n## Frequently Asked Questions (FAQs)\n\n### 1.  Where does the name \"malan\" come from?\n\nIt's an extremely nerdy name based [on a character from the Stormlight Archive series](https://coppermind.net/wiki/Malan) by Brandon Sanderson.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffreedomben%2Fmalan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffreedomben%2Fmalan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffreedomben%2Fmalan/lists"}