@@ -62,50 +62,13 @@ public abstract class AbstractFirebaseAuth {
62
62
private final Supplier <? extends FirebaseUserManager > userManager ;
63
63
private final JsonFactory jsonFactory ;
64
64
65
- protected AbstractFirebaseAuth (Builder builder ) {
65
+ protected AbstractFirebaseAuth (Builder <?> builder ) {
66
66
this .firebaseApp = checkNotNull (builder .firebaseApp );
67
67
this .tokenFactory = threadSafeMemoize (builder .tokenFactory );
68
68
this .idTokenVerifier = threadSafeMemoize (builder .idTokenVerifier );
69
69
this .cookieVerifier = threadSafeMemoize (builder .cookieVerifier );
70
70
this .userManager = threadSafeMemoize (builder .userManager );
71
- this .jsonFactory = builder .firebaseApp .getOptions ().getJsonFactory ();
72
- }
73
-
74
- protected static Builder builderFromAppAndTenantId (final FirebaseApp app , final String tenantId ) {
75
- return AbstractFirebaseAuth .builder ()
76
- .setFirebaseApp (app )
77
- .setTokenFactory (
78
- new Supplier <FirebaseTokenFactory >() {
79
- @ Override
80
- public FirebaseTokenFactory get () {
81
- return FirebaseTokenUtils .createTokenFactory (app , Clock .SYSTEM , tenantId );
82
- }
83
- })
84
- .setIdTokenVerifier (
85
- new Supplier <FirebaseTokenVerifier >() {
86
- @ Override
87
- public FirebaseTokenVerifier get () {
88
- return FirebaseTokenUtils .createIdTokenVerifier (app , Clock .SYSTEM , tenantId );
89
- }
90
- })
91
- .setCookieVerifier (
92
- new Supplier <FirebaseTokenVerifier >() {
93
- @ Override
94
- public FirebaseTokenVerifier get () {
95
- return FirebaseTokenUtils .createSessionCookieVerifier (app , Clock .SYSTEM );
96
- }
97
- })
98
- .setUserManager (
99
- new Supplier <FirebaseUserManager >() {
100
- @ Override
101
- public FirebaseUserManager get () {
102
- return FirebaseUserManager
103
- .builder ()
104
- .setFirebaseApp (app )
105
- .setTenantId (tenantId )
106
- .build ();
107
- }
108
- });
71
+ this .jsonFactory = firebaseApp .getOptions ().getJsonFactory ();
109
72
}
110
73
111
74
/**
@@ -220,6 +183,51 @@ public String execute() throws FirebaseAuthException {
220
183
};
221
184
}
222
185
186
+ /**
187
+ * Creates a new Firebase session cookie from the given ID token and options. The returned JWT can
188
+ * be set as a server-side session cookie with a custom cookie policy.
189
+ *
190
+ * @param idToken The Firebase ID token to exchange for a session cookie.
191
+ * @param options Additional options required to create the cookie.
192
+ * @return A Firebase session cookie string.
193
+ * @throws IllegalArgumentException If the ID token is null or empty, or if options is null.
194
+ * @throws FirebaseAuthException If an error occurs while generating the session cookie.
195
+ */
196
+ public String createSessionCookie (@ NonNull String idToken , @ NonNull SessionCookieOptions options )
197
+ throws FirebaseAuthException {
198
+ return createSessionCookieOp (idToken , options ).call ();
199
+ }
200
+
201
+ /**
202
+ * Similar to {@link #createSessionCookie(String, SessionCookieOptions)} but performs the
203
+ * operation asynchronously.
204
+ *
205
+ * @param idToken The Firebase ID token to exchange for a session cookie.
206
+ * @param options Additional options required to create the cookie.
207
+ * @return An {@code ApiFuture} which will complete successfully with a session cookie string. If
208
+ * an error occurs while generating the cookie or if the specified ID token is invalid, the
209
+ * future throws a {@link FirebaseAuthException}.
210
+ * @throws IllegalArgumentException If the ID token is null or empty, or if options is null.
211
+ */
212
+ public ApiFuture <String > createSessionCookieAsync (
213
+ @ NonNull String idToken , @ NonNull SessionCookieOptions options ) {
214
+ return createSessionCookieOp (idToken , options ).callAsync (firebaseApp );
215
+ }
216
+
217
+ private CallableOperation <String , FirebaseAuthException > createSessionCookieOp (
218
+ final String idToken , final SessionCookieOptions options ) {
219
+ checkNotDestroyed ();
220
+ checkArgument (!Strings .isNullOrEmpty (idToken ), "idToken must not be null or empty" );
221
+ checkNotNull (options , "options must not be null" );
222
+ final FirebaseUserManager userManager = getUserManager ();
223
+ return new CallableOperation <String , FirebaseAuthException >() {
224
+ @ Override
225
+ protected String execute () throws FirebaseAuthException {
226
+ return userManager .createSessionCookie (idToken , options );
227
+ }
228
+ };
229
+ }
230
+
223
231
/**
224
232
* Parses and verifies a Firebase ID Token.
225
233
*
@@ -320,6 +328,87 @@ FirebaseTokenVerifier getIdTokenVerifier(boolean checkRevoked) {
320
328
return verifier ;
321
329
}
322
330
331
+ /**
332
+ * Parses and verifies a Firebase session cookie.
333
+ *
334
+ * <p>If verified successfully, returns a parsed version of the cookie from which the UID and the
335
+ * other claims can be read. If the cookie is invalid, throws a {@link FirebaseAuthException}.
336
+ *
337
+ * <p>This method does not check whether the cookie has been revoked. See {@link
338
+ * #verifySessionCookie(String, boolean)}.
339
+ *
340
+ * @param cookie A Firebase session cookie string to verify and parse.
341
+ * @return A {@link FirebaseToken} representing the verified and decoded cookie.
342
+ */
343
+ public FirebaseToken verifySessionCookie (String cookie ) throws FirebaseAuthException {
344
+ return verifySessionCookie (cookie , false );
345
+ }
346
+
347
+ /**
348
+ * Parses and verifies a Firebase session cookie.
349
+ *
350
+ * <p>If {@code checkRevoked} is true, additionally verifies that the cookie has not been revoked.
351
+ *
352
+ * <p>If verified successfully, returns a parsed version of the cookie from which the UID and the
353
+ * other claims can be read. If the cookie is invalid or has been revoked while {@code
354
+ * checkRevoked} is true, throws a {@link FirebaseAuthException}.
355
+ *
356
+ * @param cookie A Firebase session cookie string to verify and parse.
357
+ * @param checkRevoked A boolean indicating whether to check if the cookie was explicitly revoked.
358
+ * @return A {@link FirebaseToken} representing the verified and decoded cookie.
359
+ */
360
+ public FirebaseToken verifySessionCookie (String cookie , boolean checkRevoked )
361
+ throws FirebaseAuthException {
362
+ return verifySessionCookieOp (cookie , checkRevoked ).call ();
363
+ }
364
+
365
+ /**
366
+ * Similar to {@link #verifySessionCookie(String)} but performs the operation asynchronously.
367
+ *
368
+ * @param cookie A Firebase session cookie string to verify and parse.
369
+ * @return An {@code ApiFuture} which will complete successfully with the parsed cookie, or
370
+ * unsuccessfully with the failure Exception.
371
+ */
372
+ public ApiFuture <FirebaseToken > verifySessionCookieAsync (String cookie ) {
373
+ return verifySessionCookieAsync (cookie , false );
374
+ }
375
+
376
+ /**
377
+ * Similar to {@link #verifySessionCookie(String, boolean)} but performs the operation
378
+ * asynchronously.
379
+ *
380
+ * @param cookie A Firebase session cookie string to verify and parse.
381
+ * @param checkRevoked A boolean indicating whether to check if the cookie was explicitly revoked.
382
+ * @return An {@code ApiFuture} which will complete successfully with the parsed cookie, or
383
+ * unsuccessfully with the failure Exception.
384
+ */
385
+ public ApiFuture <FirebaseToken > verifySessionCookieAsync (String cookie , boolean checkRevoked ) {
386
+ return verifySessionCookieOp (cookie , checkRevoked ).callAsync (firebaseApp );
387
+ }
388
+
389
+ private CallableOperation <FirebaseToken , FirebaseAuthException > verifySessionCookieOp (
390
+ final String cookie , final boolean checkRevoked ) {
391
+ checkNotDestroyed ();
392
+ checkArgument (!Strings .isNullOrEmpty (cookie ), "Session cookie must not be null or empty" );
393
+ final FirebaseTokenVerifier sessionCookieVerifier = getSessionCookieVerifier (checkRevoked );
394
+ return new CallableOperation <FirebaseToken , FirebaseAuthException >() {
395
+ @ Override
396
+ public FirebaseToken execute () throws FirebaseAuthException {
397
+ return sessionCookieVerifier .verifyToken (cookie );
398
+ }
399
+ };
400
+ }
401
+
402
+ @ VisibleForTesting
403
+ FirebaseTokenVerifier getSessionCookieVerifier (boolean checkRevoked ) {
404
+ FirebaseTokenVerifier verifier = cookieVerifier .get ();
405
+ if (checkRevoked ) {
406
+ FirebaseUserManager userManager = getUserManager ();
407
+ verifier = RevocationCheckDecorator .decorateSessionCookieVerifier (verifier , userManager );
408
+ }
409
+ return verifier ;
410
+ }
411
+
323
412
/**
324
413
* Revokes all refresh tokens for the specified user.
325
414
*
@@ -1637,19 +1726,11 @@ protected Void execute() throws FirebaseAuthException {
1637
1726
};
1638
1727
}
1639
1728
1640
- FirebaseApp getFirebaseApp () {
1641
- return this .firebaseApp ;
1642
- }
1643
-
1644
- FirebaseTokenVerifier getCookieVerifier () {
1645
- return this .cookieVerifier .get ();
1646
- }
1647
-
1648
1729
FirebaseUserManager getUserManager () {
1649
1730
return this .userManager .get ();
1650
1731
}
1651
1732
1652
- protected <T > Supplier <T > threadSafeMemoize (final Supplier <T > supplier ) {
1733
+ <T > Supplier <T > threadSafeMemoize (final Supplier <T > supplier ) {
1653
1734
return Suppliers .memoize (
1654
1735
new Supplier <T >() {
1655
1736
@ Override
@@ -1663,7 +1744,7 @@ public T get() {
1663
1744
});
1664
1745
}
1665
1746
1666
- void checkNotDestroyed () {
1747
+ private void checkNotDestroyed () {
1667
1748
synchronized (lock ) {
1668
1749
checkState (
1669
1750
!destroyed .get (),
@@ -1682,42 +1763,80 @@ final void destroy() {
1682
1763
/** Performs any additional required clean up. */
1683
1764
protected abstract void doDestroy ();
1684
1765
1685
- static Builder builder () {
1686
- return new Builder ();
1687
- }
1766
+ protected abstract static class Builder <T extends Builder <T >> {
1688
1767
1689
- static class Builder {
1690
- protected FirebaseApp firebaseApp ;
1768
+ private FirebaseApp firebaseApp ;
1691
1769
private Supplier <FirebaseTokenFactory > tokenFactory ;
1692
1770
private Supplier <? extends FirebaseTokenVerifier > idTokenVerifier ;
1693
1771
private Supplier <? extends FirebaseTokenVerifier > cookieVerifier ;
1694
- private Supplier <FirebaseUserManager > userManager ;
1772
+ private Supplier <? extends FirebaseUserManager > userManager ;
1695
1773
1696
- private Builder () {}
1774
+ protected abstract T getThis ();
1775
+
1776
+ public FirebaseApp getFirebaseApp () {
1777
+ return firebaseApp ;
1778
+ }
1697
1779
1698
- Builder setFirebaseApp (FirebaseApp firebaseApp ) {
1780
+ public T setFirebaseApp (FirebaseApp firebaseApp ) {
1699
1781
this .firebaseApp = firebaseApp ;
1700
- return this ;
1782
+ return getThis () ;
1701
1783
}
1702
1784
1703
- Builder setTokenFactory (Supplier <FirebaseTokenFactory > tokenFactory ) {
1785
+ public T setTokenFactory (Supplier <FirebaseTokenFactory > tokenFactory ) {
1704
1786
this .tokenFactory = tokenFactory ;
1705
- return this ;
1787
+ return getThis () ;
1706
1788
}
1707
1789
1708
- Builder setIdTokenVerifier (Supplier <? extends FirebaseTokenVerifier > idTokenVerifier ) {
1790
+ public T setIdTokenVerifier (Supplier <? extends FirebaseTokenVerifier > idTokenVerifier ) {
1709
1791
this .idTokenVerifier = idTokenVerifier ;
1710
- return this ;
1792
+ return getThis () ;
1711
1793
}
1712
1794
1713
- Builder setCookieVerifier (Supplier <? extends FirebaseTokenVerifier > cookieVerifier ) {
1795
+ public T setCookieVerifier (Supplier <? extends FirebaseTokenVerifier > cookieVerifier ) {
1714
1796
this .cookieVerifier = cookieVerifier ;
1715
- return this ;
1797
+ return getThis () ;
1716
1798
}
1717
1799
1718
- Builder setUserManager (Supplier <FirebaseUserManager > userManager ) {
1800
+ public T setUserManager (Supplier <FirebaseUserManager > userManager ) {
1719
1801
this .userManager = userManager ;
1720
- return this ;
1802
+ return getThis () ;
1721
1803
}
1722
1804
}
1805
+
1806
+ protected static <T extends Builder <T >> T populateBuilderFromApp (
1807
+ Builder <T > builder , final FirebaseApp app , @ Nullable final String tenantId ) {
1808
+ return builder .setFirebaseApp (app )
1809
+ .setTokenFactory (
1810
+ new Supplier <FirebaseTokenFactory >() {
1811
+ @ Override
1812
+ public FirebaseTokenFactory get () {
1813
+ return FirebaseTokenUtils .createTokenFactory (app , Clock .SYSTEM , tenantId );
1814
+ }
1815
+ })
1816
+ .setIdTokenVerifier (
1817
+ new Supplier <FirebaseTokenVerifier >() {
1818
+ @ Override
1819
+ public FirebaseTokenVerifier get () {
1820
+ return FirebaseTokenUtils .createIdTokenVerifier (app , Clock .SYSTEM , tenantId );
1821
+ }
1822
+ })
1823
+ .setCookieVerifier (
1824
+ new Supplier <FirebaseTokenVerifier >() {
1825
+ @ Override
1826
+ public FirebaseTokenVerifier get () {
1827
+ return FirebaseTokenUtils .createSessionCookieVerifier (app , Clock .SYSTEM , tenantId );
1828
+ }
1829
+ })
1830
+ .setUserManager (
1831
+ new Supplier <FirebaseUserManager >() {
1832
+ @ Override
1833
+ public FirebaseUserManager get () {
1834
+ return FirebaseUserManager
1835
+ .builder ()
1836
+ .setFirebaseApp (app )
1837
+ .setTenantId (tenantId )
1838
+ .build ();
1839
+ }
1840
+ });
1841
+ }
1723
1842
}
0 commit comments