{"id":20141266,"url":"https://github.com/alekcz/charmander","last_synced_at":"2025-04-09T18:41:12.259Z","repository":{"id":44900627,"uuid":"94308284","full_name":"alekcz/charmander","owner":"alekcz","description":"A set of libraries to make working with firebase easier in clojure","archived":false,"fork":false,"pushed_at":"2024-03-23T10:35:23.000Z","size":254,"stargazers_count":39,"open_issues_count":0,"forks_count":6,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-04-14T01:05:58.548Z","etag":null,"topics":["authentication","clojure","firebase","firebase-auth","jwt"],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alekcz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2017-06-14T08:31:21.000Z","updated_at":"2023-12-07T12:47:37.000Z","dependencies_parsed_at":"2024-04-13T20:03:31.395Z","dependency_job_id":null,"html_url":"https://github.com/alekcz/charmander","commit_stats":{"total_commits":93,"total_committers":3,"mean_commits":31.0,"dds":"0.032258064516129004","last_synced_commit":"3bb3ee940c4fccd8b8825d2e4e78288dedc02aa2"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alekcz%2Fcharmander","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alekcz%2Fcharmander/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alekcz%2Fcharmander/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alekcz%2Fcharmander/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alekcz","download_url":"https://codeload.github.com/alekcz/charmander/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247428202,"owners_count":20937430,"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":["authentication","clojure","firebase","firebase-auth","jwt"],"created_at":"2024-11-13T21:56:53.306Z","updated_at":"2025-04-09T18:41:12.238Z","avatar_url":"https://github.com/alekcz.png","language":"Clojure","readme":"# Charmander\n\nA clojure library to make working with firebase easier\n\n![master](https://github.com/alekcz/charmander/workflows/master/badge.svg) [![codecov](https://codecov.io/gh/alekcz/charmander/branch/master/graph/badge.svg)](https://codecov.io/gh/alekcz/charmander)\n\n[![Clojars Project](https://img.shields.io/clojars/v/alekcz/charmander.svg)](https://clojars.org/alekcz/charmander)\n\n## Why?\n\n- Authentication, email verification and password resets are tedious and hard. \n- Auth0 gets pricey as you scale\n- Firebase auth has a fixed cost of 0 (for now)\n\n## Usage\n\n```clojure\n\n[alekcz/charmander \"1.0.3\"]\n\n;; In your ns statement:\n(ns my.ns\n  (:require [charmander.core :as charm]\n            [charmander.admin :as charm-admin]\n            [charmander.firestore :as charm-firestore]))\n\n```\n\n## API\n- Token API\n  * `validate-token`\n\n- Admin API\n  * `init`\n  * `create-user`\n  * `delete-user`\n  * `get-user`\n  * `get-user-by-email`\n  * `get-user-by-phone-number`\n  * `set-user-email`\n  * `set-user-password`\n  * `set-user-phone-number`\n  * `set-user-display-name`\n  * `set-user-photo-url`\n  * `generate-email-verification-link`\n  * `generate-password-reset-link`\n\n- Firestore API\n  * `create-document`\n  * `add-document-to-collection`\n  * `get-document`\n  * `get-document-and-subcollections`\n  * `get-collection`\n  * `set-document`\n  * `update-document`\n  * `delete-document`\n  \n### Validating tokens\n\nValidates firebase tokens. Validating tokens doesn't require an admin or service account.\n\n```clojure\n\n(charm/validate-token \"firebase-project-id\" fresh-token)  \n;;{\n;;\t:projectid \"firebase-project-id\", \n;;\t:uid \"uid\", \n;;\t:email \"name@domain.com\", \n;;\t:email_verified false, \n;;\t:sign_in_provider \"password\", \n;;\t:exp 0000000000, \n;;\t:auth_time 0000000000\n;;}\n\n(charm/validate-token \"firebase-project-id\" stale-token)\n;; nil\n\n(charm/validate-token \"wrong-firebase-project-id\" fresh-token)\n;; nil\n\n(charm/validate-token \"(.*)-project-ids\" fresh-token)\n;;{\n;;\t:projectid \"multiple-project-ids\", \n;;\t:uid \"uid\", \n;;\t:email \"name@domain.com\", \n;;\t:email_verified false, \n;;\t:sign_in_provider \"password\", \n;;\t:exp 0000000000, \n;;\t:auth_time 0000000000\n;;}\n\n```\n\n## Admin \n\nManages user data and authentication using your firebase admin or service account credentials using the email/password sign-in provider. At the moment only one firebase app can be used at a time.   \n\nThe Admin API is based on the Java Firebase Admin SDK v6.8.0\n\n\n\n### Initializing your admin account\n\n1. Get the `json` file containing your creditials by following the instruction here [https://firebase.google.com/docs/admin/setup](https://firebase.google.com/docs/admin/setup)  \n\n2. Enable the email/password sign-in provider.\n\n3. Set the GOOGLE_CLOUD_PROJECT environment to the id of your project\n\n4. Set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the contents of your `json` key file. (Sometimes it may be necessary to wrap the key contents in single quotes to escape all the special characters within it. e.g. GOOGLE_APPLICATION_CREDENTIALS='`contents-of-json`')\n\n5. initialize the admin sdk in `charmander`\n\n```clojure\n(charm-admin/init)  \n```\n\n### Managing user accounts\nThe admin api only allows the creating of users using the email/password sign-in provider.\n\n```clojure\n\n(charm-admin/create-user \"email@domain.com\" \"superstrong6characterpassword\")  \n;;{   \n;;    :email email@domain.com\n;;    :email-verified false\n;;    :uid vMnMJvS28kWr5pb6sByHULMLelJ3\n;;    :provider-id firebase\n;;    :photo-url nil\n;;    :phone-number nil\n;;    :display-name nil\n;;    :disabled false\n;;}\n\n(charm-admin/create-user \"email@domain.com\" \"superstrong6characterpassword\" \"my-very-own-custom-uuid\")  \n;;{   \n;;    :email email@domain.com\n;;    :email-verified false\n;;    :uid my-very-own-custom-uuid\n;;    :provider-id firebase\n;;    :photo-url nil\n;;    :phone-number nil\n;;    :display-name nil\n;;    :disabled false\n;;}\n\n(charm-admin/get-user \"vMnMJvS28kWr5pb6sByHULMLelJ3\")  \n;;{   \n;;    :email email@domain.com\n;;    :email-verified true\n;;    :uid vMnMJvS28kWr5pb6sByHULMLelJ3\n;;    :provider-id firebase\n;;    :photo-url https://avatars0.githubusercontent.com/u/11717556?s=460\u0026v=4\n;;    :phone-number nil\n;;    :display-name emailer\n;;    :disabled false\n;;}\n\n(charm-admin/get-user-by-email \"email@domain.com\")  \n;;{   \n;;    :email email@domain.com\n;;    :email-verified true\n;;    :uid vMnMJvS28kWr5pb6sByHULMLelJ3\n;;    :provider-id firebase\n;;    :photo-url https://avatars0.githubusercontent.com/u/11717556?s=460\u0026v=4\n;;    :phone-number nil\n;;    :display-name emailer\n;;    :disabled false\n;;}\n\n(charm-admin/set-user-email \"vMnMJvS28kWr5pb6sByHULMLelJ3\" \"tony@hawk.cool\")  \n;;{   \n;;    :email tony@hawk.cool\n;;    :email-verified false\n;;    :uid vMnMJvS28kWr5pb6sByHULMLelJ3\n;;    :provider-id firebase\n;;    :photo-url https://avatars0.githubusercontent.com/u/11717556?s=460\u0026v=4\n;;    :phone-number nil\n;;    :display-name emailer\n;;    :disabled false\n;;}\n\n(charm-admin/set-user-password \"vMnMJvS28kWr5pb6sByHULMLelJ3\" \"5tr0ngp455w0rd\")  \n;;{   \n;;    :email tony@hawk.cool\n;;    :email-verified false\n;;    :uid vMnMJvS28kWr5pb6sByHULMLelJ3\n;;    :provider-id firebase\n;;    :photo-url https://avatars0.githubusercontent.com/u/11717556?s=460\u0026v=4\n;;    :phone-number nil\n;;    :display-name emailer\n;;    :disabled false\n;;}\n\n(charm-admin/set-user-phone-number \"vMnMJvS28kWr5pb6sByHULMLelJ3\" \"0800123123\")  \n;;{   \n;;    :email tony@hawk.cool\n;;    :email-verified false\n;;    :uid vMnMJvS28kWr5pb6sByHULMLelJ3\n;;    :provider-id firebase\n;;    :photo-url https://avatars0.githubusercontent.com/u/11717556?s=460\u0026v=4\n;;    :phone-number 0800123123\n;;    :display-name emailer\n;;    :disabled false\n;;}\n\n(charm-admin/set-user-display-name \"vMnMJvS28kWr5pb6sByHULMLelJ3\" \"Tony Hawk\")  \n;;{   \n;;    :email tony@hawk.cool\n;;    :email-verified false\n;;    :uid vMnMJvS28kWr5pb6sByHULMLelJ3\n;;    :provider-id firebase\n;;    :photo-url https://avatars0.githubusercontent.com/u/11717556?s=460\u0026v=4\n;;    :phone-number nil\n;;    :display-name Tony Hawk\n;;    :disabled false\n;;}\n\n(charm-admin/set-user-photo-url \"vMnMJvS28kWr5pb6sByHULMLelJ3\" \"https://en.wikipedia.org/wiki/Tony_Hawk#/media/File:Skater_Tony_Hawk.jpg\")  \n;;{   \n;;    :email tony@hawk.cool\n;;    :email-verified false\n;;    :uid vMnMJvS28kWr5pb6sByHULMLelJ3\n;;    :provider-id firebase\n;;    :photo-url https://en.wikipedia.org/wiki/Tony_Hawk#/media/File:Skater_Tony_Hawk.jpg\n;;    :phone-number nil\n;;    :display-name Tony Hawk\n;;    :disabled false\n;;}\n\n(charm-admin/generate-email-verification-link \"tony@hawk.cool\")  \n;; https://alekcz-dev.firebaseapp.com/__/auth/action?mode=verifyEmail\u0026oobCode=d6uX0gzOuvnZLAwfk8HKxLYrRUCUaBnrzwDgFdzfDhgAAAFprFHVmQ\u0026apiKey=AIz0000yaVaaa512312YL_lffaf311da333211TBp_QPFqvda2e1daw\u0026lang=en\n\n\n(charm-admin/generate-password-reset-link \"tony@hawk.cool\")  \n;; https://alekcz-dev.firebaseapp.com/__/auth/action?mode=resetPassword\u0026oobCode=viRcZqjCqxN6eYYmkQGY2fCZjU4RDKuNhysok83ghSEAAAFprFVwJg\u0026apiKey=AIz0000yaVaaa512312YL_lffaf311da333211TBp_QPFqvda2e1daww\u0026lang=en\n\n```\n\n### Working with Firestore (Alpha)\nThe API allows for CRUD operation on firestore.\n\n```clojure\n\n(charm-firestore/create-document \"collection\" \"document\" {:field1 \"field1\" :field2 \"field2\"})  \n;;nil\n\n(charm-firestore/add-document-to-collection \"path/to/collection\" {:field1 \"field1\" :field2 \"field2\"})  \n;;  { :id \"document\",\n;;    :data {\n;;          :name \"Document\",\n;;          :subcollections ()\n;;     }\n;;  }\n\n(charm-firestore/push-document-to-collection \"path/to/collection\" {:field1 \"field1\" :field2 \"field2\"})  \n;; nil\n;; To allow increased through put this writes to firebase but gives not feedback.\n\n(charm-firestore/get-document \"path/to/collection\" \"document\")  \n;;  { :id \"document\",\n;;    :data {\n;;          :name \"Document\",\n;;          :subcollections\n;;           ({:id \"subcollection1\", :path \"collection/document/subcollection1\"}\n;;            {:id \"subcollection2\", :path \"collection/document/subcollection2\"}\n;;            {:id \"subcollection3\", :path \"collection/document/subcollection2\"})\n;;     }\n;;  }\n\n(charm-firestore/get-document-and-subcollections \"path/to/collection\" \"document\")  \n;;  { :id \"document\",\n;;    :data {\n;;          :name \"Document\",\n;;          :subcollections\n;;           ({:id \"subcollection1\", \n;;             :path \"collection/document/subcollection1\"\n;;             :data ({:id \"9AMN2yNG3J9GvtTPMxxy\", :data {:name \"SubdocumentA\"}})}\n;;            {:id \"subcollection2\", \n;;             :path \"collection/document/subcollection1\"\n;;             :data ({:id \"6223N2yNG3J9GvtTPMxxy\", :data {:name \"SubdocumentB\"}})})\n;;             \n;;     }\n;;  }\n\n(charm-firestore/get-collection \"path/to/collection\")  \n;;     ({:id \"collectionA\", \n;;       :path \"collection/document/collectionA\"\n;;       :data ({:id \"6223N2yNG3J9GvtTPMxxy\", :data {:name \"SubdocumentP\"}}\n;;              {:id \"6223N2yNG3J9GvtTPMxxy\", :data {:name \"SubdocumentQ\"}}))})\n\n(charm-firestore/set-document \"path/to/document-to-be-overwritten\" {:field1 \"field1\" :field2 \"field2\"})  \n;;nil\n\n(charm-firestore/update-document \"path/to/document-to-be-updated\" {:field1 \"field1\" :field2 \"field2\"})  \n;;nil\n\n(charm-firestore/delete-document \"path/to/document-to-be-delete\")  \n;;nil\n```\n\n## Next steps\n\n- Increase efficiency\n- Look into core.async for public key refresh\n- Build up API \n\n## License\n\nCopyright © 2019 Alexander Oloo\n\nDistributed under the Eclipse Public License either version 1.0 or (at\nyour option) any later version.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falekcz%2Fcharmander","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falekcz%2Fcharmander","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falekcz%2Fcharmander/lists"}