Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/alekcz/charmander
A set of libraries to make working with firebase easier in clojure
https://github.com/alekcz/charmander
authentication clojure firebase firebase-auth jwt
Last synced: about 1 month ago
JSON representation
A set of libraries to make working with firebase easier in clojure
- Host: GitHub
- URL: https://github.com/alekcz/charmander
- Owner: alekcz
- License: epl-1.0
- Created: 2017-06-14T08:31:21.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2024-03-23T10:35:23.000Z (9 months ago)
- Last Synced: 2024-04-14T01:05:58.548Z (8 months ago)
- Topics: authentication, clojure, firebase, firebase-auth, jwt
- Language: Clojure
- Size: 248 KB
- Stars: 39
- Watchers: 5
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Charmander
A clojure library to make working with firebase easier
![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)
[![Clojars Project](https://img.shields.io/clojars/v/alekcz/charmander.svg)](https://clojars.org/alekcz/charmander)
## Why?
- Authentication, email verification and password resets are tedious and hard.
- Auth0 gets pricey as you scale
- Firebase auth has a fixed cost of 0 (for now)## Usage
```clojure
[alekcz/charmander "1.0.3"]
;; In your ns statement:
(ns my.ns
(:require [charmander.core :as charm]
[charmander.admin :as charm-admin]
[charmander.firestore :as charm-firestore]))```
## API
- Token API
* `validate-token`- Admin API
* `init`
* `create-user`
* `delete-user`
* `get-user`
* `get-user-by-email`
* `get-user-by-phone-number`
* `set-user-email`
* `set-user-password`
* `set-user-phone-number`
* `set-user-display-name`
* `set-user-photo-url`
* `generate-email-verification-link`
* `generate-password-reset-link`- Firestore API
* `create-document`
* `add-document-to-collection`
* `get-document`
* `get-document-and-subcollections`
* `get-collection`
* `set-document`
* `update-document`
* `delete-document`
### Validating tokensValidates firebase tokens. Validating tokens doesn't require an admin or service account.
```clojure
(charm/validate-token "firebase-project-id" fresh-token)
;;{
;; :projectid "firebase-project-id",
;; :uid "uid",
;; :email "[email protected]",
;; :email_verified false,
;; :sign_in_provider "password",
;; :exp 0000000000,
;; :auth_time 0000000000
;;}(charm/validate-token "firebase-project-id" stale-token)
;; nil(charm/validate-token "wrong-firebase-project-id" fresh-token)
;; nil(charm/validate-token "(.*)-project-ids" fresh-token)
;;{
;; :projectid "multiple-project-ids",
;; :uid "uid",
;; :email "[email protected]",
;; :email_verified false,
;; :sign_in_provider "password",
;; :exp 0000000000,
;; :auth_time 0000000000
;;}```
## Admin
Manages 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.
The Admin API is based on the Java Firebase Admin SDK v6.8.0
### Initializing your admin account
1. 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)
2. Enable the email/password sign-in provider.
3. Set the GOOGLE_CLOUD_PROJECT environment to the id of your project
4. 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`')
5. initialize the admin sdk in `charmander`
```clojure
(charm-admin/init)
```### Managing user accounts
The admin api only allows the creating of users using the email/password sign-in provider.```clojure
(charm-admin/create-user "[email protected]" "superstrong6characterpassword")
;;{
;; :email [email protected]
;; :email-verified false
;; :uid vMnMJvS28kWr5pb6sByHULMLelJ3
;; :provider-id firebase
;; :photo-url nil
;; :phone-number nil
;; :display-name nil
;; :disabled false
;;}(charm-admin/create-user "[email protected]" "superstrong6characterpassword" "my-very-own-custom-uuid")
;;{
;; :email [email protected]
;; :email-verified false
;; :uid my-very-own-custom-uuid
;; :provider-id firebase
;; :photo-url nil
;; :phone-number nil
;; :display-name nil
;; :disabled false
;;}(charm-admin/get-user "vMnMJvS28kWr5pb6sByHULMLelJ3")
;;{
;; :email [email protected]
;; :email-verified true
;; :uid vMnMJvS28kWr5pb6sByHULMLelJ3
;; :provider-id firebase
;; :photo-url https://avatars0.githubusercontent.com/u/11717556?s=460&v=4
;; :phone-number nil
;; :display-name emailer
;; :disabled false
;;}(charm-admin/get-user-by-email "[email protected]")
;;{
;; :email [email protected]
;; :email-verified true
;; :uid vMnMJvS28kWr5pb6sByHULMLelJ3
;; :provider-id firebase
;; :photo-url https://avatars0.githubusercontent.com/u/11717556?s=460&v=4
;; :phone-number nil
;; :display-name emailer
;; :disabled false
;;}(charm-admin/set-user-email "vMnMJvS28kWr5pb6sByHULMLelJ3" "[email protected]")
;;{
;; :email [email protected]
;; :email-verified false
;; :uid vMnMJvS28kWr5pb6sByHULMLelJ3
;; :provider-id firebase
;; :photo-url https://avatars0.githubusercontent.com/u/11717556?s=460&v=4
;; :phone-number nil
;; :display-name emailer
;; :disabled false
;;}(charm-admin/set-user-password "vMnMJvS28kWr5pb6sByHULMLelJ3" "5tr0ngp455w0rd")
;;{
;; :email [email protected]
;; :email-verified false
;; :uid vMnMJvS28kWr5pb6sByHULMLelJ3
;; :provider-id firebase
;; :photo-url https://avatars0.githubusercontent.com/u/11717556?s=460&v=4
;; :phone-number nil
;; :display-name emailer
;; :disabled false
;;}(charm-admin/set-user-phone-number "vMnMJvS28kWr5pb6sByHULMLelJ3" "0800123123")
;;{
;; :email [email protected]
;; :email-verified false
;; :uid vMnMJvS28kWr5pb6sByHULMLelJ3
;; :provider-id firebase
;; :photo-url https://avatars0.githubusercontent.com/u/11717556?s=460&v=4
;; :phone-number 0800123123
;; :display-name emailer
;; :disabled false
;;}(charm-admin/set-user-display-name "vMnMJvS28kWr5pb6sByHULMLelJ3" "Tony Hawk")
;;{
;; :email [email protected]
;; :email-verified false
;; :uid vMnMJvS28kWr5pb6sByHULMLelJ3
;; :provider-id firebase
;; :photo-url https://avatars0.githubusercontent.com/u/11717556?s=460&v=4
;; :phone-number nil
;; :display-name Tony Hawk
;; :disabled false
;;}(charm-admin/set-user-photo-url "vMnMJvS28kWr5pb6sByHULMLelJ3" "https://en.wikipedia.org/wiki/Tony_Hawk#/media/File:Skater_Tony_Hawk.jpg")
;;{
;; :email [email protected]
;; :email-verified false
;; :uid vMnMJvS28kWr5pb6sByHULMLelJ3
;; :provider-id firebase
;; :photo-url https://en.wikipedia.org/wiki/Tony_Hawk#/media/File:Skater_Tony_Hawk.jpg
;; :phone-number nil
;; :display-name Tony Hawk
;; :disabled false
;;}(charm-admin/generate-email-verification-link "[email protected]")
;; https://alekcz-dev.firebaseapp.com/__/auth/action?mode=verifyEmail&oobCode=d6uX0gzOuvnZLAwfk8HKxLYrRUCUaBnrzwDgFdzfDhgAAAFprFHVmQ&apiKey=AIz0000yaVaaa512312YL_lffaf311da333211TBp_QPFqvda2e1daw&lang=en(charm-admin/generate-password-reset-link "[email protected]")
;; https://alekcz-dev.firebaseapp.com/__/auth/action?mode=resetPassword&oobCode=viRcZqjCqxN6eYYmkQGY2fCZjU4RDKuNhysok83ghSEAAAFprFVwJg&apiKey=AIz0000yaVaaa512312YL_lffaf311da333211TBp_QPFqvda2e1daww&lang=en```
### Working with Firestore (Alpha)
The API allows for CRUD operation on firestore.```clojure
(charm-firestore/create-document "collection" "document" {:field1 "field1" :field2 "field2"})
;;nil(charm-firestore/add-document-to-collection "path/to/collection" {:field1 "field1" :field2 "field2"})
;; { :id "document",
;; :data {
;; :name "Document",
;; :subcollections ()
;; }
;; }(charm-firestore/push-document-to-collection "path/to/collection" {:field1 "field1" :field2 "field2"})
;; nil
;; To allow increased through put this writes to firebase but gives not feedback.(charm-firestore/get-document "path/to/collection" "document")
;; { :id "document",
;; :data {
;; :name "Document",
;; :subcollections
;; ({:id "subcollection1", :path "collection/document/subcollection1"}
;; {:id "subcollection2", :path "collection/document/subcollection2"}
;; {:id "subcollection3", :path "collection/document/subcollection2"})
;; }
;; }(charm-firestore/get-document-and-subcollections "path/to/collection" "document")
;; { :id "document",
;; :data {
;; :name "Document",
;; :subcollections
;; ({:id "subcollection1",
;; :path "collection/document/subcollection1"
;; :data ({:id "9AMN2yNG3J9GvtTPMxxy", :data {:name "SubdocumentA"}})}
;; {:id "subcollection2",
;; :path "collection/document/subcollection1"
;; :data ({:id "6223N2yNG3J9GvtTPMxxy", :data {:name "SubdocumentB"}})})
;;
;; }
;; }(charm-firestore/get-collection "path/to/collection")
;; ({:id "collectionA",
;; :path "collection/document/collectionA"
;; :data ({:id "6223N2yNG3J9GvtTPMxxy", :data {:name "SubdocumentP"}}
;; {:id "6223N2yNG3J9GvtTPMxxy", :data {:name "SubdocumentQ"}}))})(charm-firestore/set-document "path/to/document-to-be-overwritten" {:field1 "field1" :field2 "field2"})
;;nil(charm-firestore/update-document "path/to/document-to-be-updated" {:field1 "field1" :field2 "field2"})
;;nil(charm-firestore/delete-document "path/to/document-to-be-delete")
;;nil
```## Next steps
- Increase efficiency
- Look into core.async for public key refresh
- Build up API## License
Copyright © 2019 Alexander Oloo
Distributed under the Eclipse Public License either version 1.0 or (at
your option) any later version.