@@ -62,50 +62,13 @@ public abstract class AbstractFirebaseAuth {
6262 private final Supplier <? extends FirebaseUserManager > userManager ;
6363 private final JsonFactory jsonFactory ;
6464
65- protected AbstractFirebaseAuth (Builder builder ) {
65+ protected AbstractFirebaseAuth (Builder <?> builder ) {
6666 this .firebaseApp = checkNotNull (builder .firebaseApp );
6767 this .tokenFactory = threadSafeMemoize (builder .tokenFactory );
6868 this .idTokenVerifier = threadSafeMemoize (builder .idTokenVerifier );
6969 this .cookieVerifier = threadSafeMemoize (builder .cookieVerifier );
7070 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 ();
10972 }
11073
11174 /**
@@ -220,6 +183,51 @@ public String execute() throws FirebaseAuthException {
220183 };
221184 }
222185
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+
223231 /**
224232 * Parses and verifies a Firebase ID Token.
225233 *
@@ -320,6 +328,87 @@ FirebaseTokenVerifier getIdTokenVerifier(boolean checkRevoked) {
320328 return verifier ;
321329 }
322330
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+
323412 /**
324413 * Revokes all refresh tokens for the specified user.
325414 *
@@ -1637,19 +1726,11 @@ protected Void execute() throws FirebaseAuthException {
16371726 };
16381727 }
16391728
1640- FirebaseApp getFirebaseApp () {
1641- return this .firebaseApp ;
1642- }
1643-
1644- FirebaseTokenVerifier getCookieVerifier () {
1645- return this .cookieVerifier .get ();
1646- }
1647-
16481729 FirebaseUserManager getUserManager () {
16491730 return this .userManager .get ();
16501731 }
16511732
1652- protected <T > Supplier <T > threadSafeMemoize (final Supplier <T > supplier ) {
1733+ <T > Supplier <T > threadSafeMemoize (final Supplier <T > supplier ) {
16531734 return Suppliers .memoize (
16541735 new Supplier <T >() {
16551736 @ Override
@@ -1663,7 +1744,7 @@ public T get() {
16631744 });
16641745 }
16651746
1666- void checkNotDestroyed () {
1747+ private void checkNotDestroyed () {
16671748 synchronized (lock ) {
16681749 checkState (
16691750 !destroyed .get (),
@@ -1682,42 +1763,80 @@ final void destroy() {
16821763 /** Performs any additional required clean up. */
16831764 protected abstract void doDestroy ();
16841765
1685- static Builder builder () {
1686- return new Builder ();
1687- }
1766+ protected abstract static class Builder <T extends Builder <T >> {
16881767
1689- static class Builder {
1690- protected FirebaseApp firebaseApp ;
1768+ private FirebaseApp firebaseApp ;
16911769 private Supplier <FirebaseTokenFactory > tokenFactory ;
16921770 private Supplier <? extends FirebaseTokenVerifier > idTokenVerifier ;
16931771 private Supplier <? extends FirebaseTokenVerifier > cookieVerifier ;
1694- private Supplier <FirebaseUserManager > userManager ;
1772+ private Supplier <? extends FirebaseUserManager > userManager ;
16951773
1696- private Builder () {}
1774+ protected abstract T getThis ();
1775+
1776+ public FirebaseApp getFirebaseApp () {
1777+ return firebaseApp ;
1778+ }
16971779
1698- Builder setFirebaseApp (FirebaseApp firebaseApp ) {
1780+ public T setFirebaseApp (FirebaseApp firebaseApp ) {
16991781 this .firebaseApp = firebaseApp ;
1700- return this ;
1782+ return getThis () ;
17011783 }
17021784
1703- Builder setTokenFactory (Supplier <FirebaseTokenFactory > tokenFactory ) {
1785+ public T setTokenFactory (Supplier <FirebaseTokenFactory > tokenFactory ) {
17041786 this .tokenFactory = tokenFactory ;
1705- return this ;
1787+ return getThis () ;
17061788 }
17071789
1708- Builder setIdTokenVerifier (Supplier <? extends FirebaseTokenVerifier > idTokenVerifier ) {
1790+ public T setIdTokenVerifier (Supplier <? extends FirebaseTokenVerifier > idTokenVerifier ) {
17091791 this .idTokenVerifier = idTokenVerifier ;
1710- return this ;
1792+ return getThis () ;
17111793 }
17121794
1713- Builder setCookieVerifier (Supplier <? extends FirebaseTokenVerifier > cookieVerifier ) {
1795+ public T setCookieVerifier (Supplier <? extends FirebaseTokenVerifier > cookieVerifier ) {
17141796 this .cookieVerifier = cookieVerifier ;
1715- return this ;
1797+ return getThis () ;
17161798 }
17171799
1718- Builder setUserManager (Supplier <FirebaseUserManager > userManager ) {
1800+ public T setUserManager (Supplier <FirebaseUserManager > userManager ) {
17191801 this .userManager = userManager ;
1720- return this ;
1802+ return getThis () ;
17211803 }
17221804 }
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+ }
17231842}
0 commit comments