@hackage / firebase-hs

Firebase Auth, Firestore, and Servant integration for Haskell

Latest0.3.0.0

Changelog

Changelog

0.3.0.0

Fixed
  • Percent-encode every caller-supplied URL component. Project IDs, collection paths, document IDs, and updateMask field paths were interpolated raw, so a value containing ?, #, %, &, a space, or any non-ASCII character produced a malformed request or injected query parameters. Subcollection / separators are preserved; the segments between them are encoded.
  • FirestoreValue covers every type Firestore stores. bytesValue, referenceValue, and geoPointValue had no representation, so a document containing any of them failed to decode outright and getDocument returned InvalidResponse for data Firestore considers perfectly valid.
  • Non-finite doubles travel in proto3 JSON's string spellings. DoubleValue holding NaN or an infinity previously encoded as null or "+inf", which Firestore rejects, and a stored "NaN", "Infinity", or "-Infinity" failed to decode, making any document that held one unreadable.
  • runQuery posts to the queried collection's parent resource, so a subcollection path (users/abc/posts) now queries that subcollection. The full path used to be sent as the from collection ID, which Firestore rejects; only top-level collections were queryable.
  • A query result whose document fails to decode is reported as InvalidResponse instead of being silently dropped, which misreported what the query matched.
  • integerValue strings outside the Int64 range are rejected. The digits were read straight into Int64, so an out-of-range value silently wrapped instead of failing.
  • {"doubleValue": null} is rejected. The null previously fell through to aeson's Double parser, which reads JSON null as NaN.
  • A cache refresh no longer overwrites a newer key set installed by a concurrent verification.
  • runQuery and runQueryInTransaction classify their error responses. Firestore's streaming endpoints frame an error as a single-element JSON array, which the parser did not read, so a query that failed with an error response surfaced as NetworkError "HTTP <status>" instead of DocumentNotFound, PermissionDenied, TransactionAborted, or a specific API error.
  • A query stream that fails after emitting some results reports the error instead of returning the partial page as a success. The trailing error entry was dropped, so a truncated result set looked complete.
  • TimestampValue encodes at most nanosecond precision. A UTCTime carrying sub-nanosecond digits formatted to more than the nine fractional digits Firestore accepts, which it rejects on write.
Breaking Changes
  • Firestore operations take a single Firestore handle in place of the Manager -> AccessToken -> ProjectId prefix every one of them repeated. Build it with newFirestore, and refresh an expiring token with withToken rather than rebuilding the connection pool.
  • FirebaseUser gained fields, so positional construction no longer compiles. Pattern matches on fuUid, fuEmail, and fuName are unaffected.
  • commitTransaction and the runTransaction callback take the new opaque Write type in place of raw Aeson.Value, with mkUpdateWrite and mkDeleteWrite constructing it. Hand-assembled write JSON no longer typechecks.
  • Firebase.Firestore.Internal.queryUrl is replaced by runQueryUrl, which takes the queried collection so it can address the parent resource.
  • KeyCache is now backed by IORef rather than TVar, and Firebase.Auth re-exports it as an abstract type. Construct it with newKeyCache or newTlsKeyCache.
  • Dropped the stm dependency: the cache is a single reference with no composed transactions, which atomicModifyIORef' covers.
  • Dropped the mtl dependency from the servant flag. Firebase.Servant now builds its 401 on the Handler newtype and transformers, which does not depend on which MonadError re-export a given servant version ships.
  • Firebase.Servant no longer exports extractBearerToken or authErrorToBody. Both were duplicates of the Firebase.Auth.WAI versions; use Firebase.Auth.Internal.bearerToken and Firebase.Auth.authErrorMessage.
  • A response body that is JSON but not shaped like a Firestore error now reports NetworkError "HTTP <status>" instead of FirestoreApiError status "" "unknown error".
Added
  • getDocumentInTransaction and runQueryInTransaction read inside a transaction. The reads see the transaction's snapshot and Firestore verifies at commit that nothing they read has changed, which is what makes runTransaction a transaction rather than an atomic batch write; reads without the transaction ID never did either.
  • Token claims are no longer discarded. FirebaseUser now carries fuEmailVerified, fuPicture, fuAuthTime, fuSignInProvider, and fuCustomClaims, with hasClaim and lookupClaim to read them. Custom claims are how Firebase expresses roles, so without them a verified token could establish identity but not authorize anything.
  • 401 responses from the WAI middleware and the Servant handler carry the WWW-Authenticate: Bearer challenge RFC 6750 requires.
  • listDocuments lists a collection. collectionUrl had described itself as "used for listing" since the first release with nothing to use it.
  • BytesValue, ReferenceValue, GeoPointValue, and the GeoPoint type.
  • mkUpdateWrite and mkDeleteWrite build the writes commitTransaction and runTransaction expect. mkUpdateWrite was referenced by the README and Haddock but never existed, leaving no supported way to construct a write.
  • Firebase.Auth.Internal: base64url padding and bearer-token extraction, shared by the verifier and both web integrations.
  • authErrorMessage renders an AuthError as a client-safe body.
  • documentResourceName, the percent-encoding helpers, splitCollectionPath, documentInTransactionUrl, and the pure response decoders (decodeBody, decodeDocumentList, decodeQueryResults, decodeTransactionId) are exported from Firebase.Firestore.Internal.
Changed
  • Bearer scheme names are matched case-insensitively, as RFC 7235 requires.
  • Network calls catch only HttpException. Anything else, asynchronous cancellation in particular, propagates instead of surfacing as a KeyFetchError or NetworkError result.
  • Widened bounds: http-client-tls < 0.5 (resolves the Stackage report in issue #1), containers < 0.9, aeson < 2.4, time < 1.17, crypton < 2. Lowered base to >= 4.18, admitting GHC 9.6.
  • http-client >= 0.7.13, the first release whose Show Request redacts the Authorization header. An HttpException rendered into NetworkError text therefore never carries the access token.
  • CI builds the wai and servant modules, which no job previously compiled, and adds a GHC compatibility matrix, an sdist build, and an ASCII-only source check.

0.2.0.0

Breaking Changes
  • Replaced jose JWT backend with direct crypton RS256 verification
  • Dropped jose, lens, memory dependencies for a significantly lighter dependency tree
  • JWKSet (from jose) replaced with internal JwkSet/JwkKey types in Firebase.Auth.Types
  • License changed from MIT to BSD-3-Clause
Added
  • JwkSet and JwkKey types for Google's public key representation
  • Manual JWT parsing with base64-bytestring (no jose overhead)
  • RS256 signature verification via crypton (Crypto.PubKey.RSA.PKCS15)
Changed
  • Bumped GHC to 9.8.4, base >= 4.19
  • Widened stm bounds to < 2.7
  • Widened text bounds to >= 1.2 && < 2.2
  • Compatible with modern Haskell crypto stack (crypton)
Removed
  • jose dependency (source of memory/ram incompatibility)
  • lens dependency (only used for jose's API)
  • FirebaseClaims, HasClaimsSet internal types (replaced with direct JSON parsing)
Unchanged
  • Public API for verifyIdToken, verifyIdTokenCached, newKeyCache, newTlsKeyCache
  • FirebaseConfig, FirebaseUser, AuthError, KeyCache types
  • WAI middleware (Firebase.Auth.WAI)
  • Servant combinator (Firebase.Servant)
  • Firestore client (all modules unchanged)
  • All 46 tests pass

0.1.1.0

Fixed
  • Import throwError from Control.Monad.Except (mtl) instead of Servant.Server re-export for compatibility with newer servant versions
  • Add explicit mtl dependency under servant flag

0.1.0.0

Initial release.

Auth
  • Firebase ID token (JWT) verification against Google's public keys
  • RS256 signature validation via jose
  • JWK-based key fetching with Cache-Control: max-age caching
  • STM-backed KeyCache for thread-safe concurrent verification
  • Full claims validation: issuer, audience, expiry, issued-at, subject
  • Configurable clock skew (default 300s)
Firestore REST API Client
  • CRUD operations: getDocument, createDocument, updateDocument, deleteDocument
  • Structured query DSL with composable builder pattern
  • Composite filters for complex query conditions
  • FirestoreValue ADT with custom JSON instances matching Firestore's tagged wire format
Atomic Transactions
  • beginTransaction, commitTransaction, rollbackTransaction for manual control
  • runTransaction for automatic begin/commit/rollback with callback
  • TransactionMode sum type: ReadWrite, RetryWith, ReadOnly
WAI Auth Middleware (optional, wai flag)
  • requireAuth, firebaseAuth, lookupFirebaseUser
Servant Auth Combinator (optional, servant flag)
  • firebaseAuthHandler, extractBearerToken, authErrorToBody
Internal
  • Pure URL builders and error parsers in Firebase.Firestore.Internal
  • 41 pure tests