Check out what’s new from Firebase@ Google I/O 2021, and join our alpha program for early access to the new Remote Config personalization feature. Learn more

נהל עוגיות מושב

Firebase Auth מספק ניהול עוגיות הפעלה בצד השרת לאתרים מסורתיים המסתמכים על עוגיות הפעלה. לפיתרון זה ישנם מספר יתרונות ביחס לאסימוני זיהוי קצרי מועד בצד הלקוח, אשר עשויים לדרוש מנגנון הפניה בכל פעם מחדש כדי לעדכן את קובץ ה- cookie של ההפעלה בתום תפוגתם:

  • אבטחה משופרת באמצעות אסימוני הפעלה מבוססי JWT שניתן ליצור רק באמצעות חשבונות שירות מורשים.
  • קובצי Cookie ללא הפעלות שמגיעים עם כל היתרון של שימוש ב- JWT לאימות. לקובץ ה- cookie של ההפעלה יש אותן טענות (כולל תביעות מותאמות אישית) כמו אסימון הזיהוי, מה שהופך את אותן בדיקות ההרשאה לאכיפיות על קובצי ה- cookie.
  • יכולת ליצור עוגיות הפעלה עם זמני תפוגה מותאמים אישית הנעים בין 5 דקות לשבועיים.
  • גמישות לאכיפת מדיניות קובצי cookie בהתבסס על דרישות היישום: תחום, נתיב, מאובטח, httpOnly וכו '.
  • יכולת לבטל קובצי cookie בהפעלה כאשר יש חשד לגניבת אסימונים באמצעות ממשק ה- API לביטול רענון אסימון.
  • יכולת לזהות ביטול הפעלות בשינויים משמעותיים בחשבון.

להתחבר

בהנחה שהיישום משתמש בעוגיות httpOnly בצד השרת, היכנס למשתמש בדף הכניסה באמצעות ערכות ה- SDK של הלקוח. נוצר אסימון מזהה Firebase, ואז אסימון המזהה נשלח באמצעות HTTP POST לנקודת סיום כניסה של הפעלה, כאשר נוצר באמצעות קובץ ה- cookie של מנהל המערכת קובץ cookie של הפעלה. בהצלחה, יש לנקות את המדינה מאחסון הצד של הלקוח.

firebase.initializeApp({
  apiKey: 'AIza…',
  authDomain: '<PROJECT_ID>.firebasepp.com'
});

// As httpOnly cookies are to be used, do not persist any state client side.
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE);

// When the user signs in with email and password.
firebase.auth().signInWithEmailAndPassword('user@example.com', 'password').then(user => {
  // Get the user's ID token as it is needed to exchange for a session cookie.
  return user.getIdToken().then(idToken = > {
    // Session login endpoint is queried and the session cookie is set.
    // CSRF protection should be taken into account.
    // ...
    const csrfToken = getCookie('csrfToken')
    return postIdTokenToSessionLogin('/sessionLogin', idToken, csrfToken);
  });
}).then(() => {
  // A page redirect would suffice as the persistence is set to NONE.
  return firebase.auth().signOut();
}).then(() => {
  window.location.assign('/profile');
});

כדי ליצור קובץ cookie של הפעלה בתמורה לאסימון המזהה שסופק, נדרשת נקודת קצה של HTTP. שלח את האסימון לנקודת הסיום, והגדר זמן משך פעילות מותאם אישית באמצעות ה- SDK של מנהל ה Firebase. יש לנקוט באמצעים מתאימים למניעת התקפות זיוף בקשות חוצות אתרים (CSRF).

Node.js

app.post('/sessionLogin', (req, res) => {
  // Get the ID token passed and the CSRF token.
  const idToken = req.body.idToken.toString();
  const csrfToken = req.body.csrfToken.toString();
  // Guard against CSRF attacks.
  if (csrfToken !== req.cookies.csrfToken) {
    res.status(401).send('UNAUTHORIZED REQUEST!');
    return;
  }
  // Set session expiration to 5 days.
  const expiresIn = 60 * 60 * 24 * 5 * 1000;
  // Create the session cookie. This will also verify the ID token in the process.
  // The session cookie will have the same claims as the ID token.
  // To only allow session cookie setting on recent sign-in, auth_time in ID token
  // can be checked to ensure user was recently signed in before creating a session cookie.
  admin
    .auth()
    .createSessionCookie(idToken, { expiresIn })
    .then(
      (sessionCookie) => {
        // Set cookie policy for session cookie.
        const options = { maxAge: expiresIn, httpOnly: true, secure: true };
        res.cookie('session', sessionCookie, options);
        res.end(JSON.stringify({ status: 'success' }));
      },
      (error) => {
        res.status(401).send('UNAUTHORIZED REQUEST!');
      }
    );
});

ג'אווה

@POST
@Path("/sessionLogin")
@Consumes("application/json")
public Response createSessionCookie(LoginRequest request) {
  // Get the ID token sent by the client
  String idToken = request.getIdToken();
  // Set session expiration to 5 days.
  long expiresIn = TimeUnit.DAYS.toMillis(5);
  SessionCookieOptions options = SessionCookieOptions.builder()
      .setExpiresIn(expiresIn)
      .build();
  try {
    // Create the session cookie. This will also verify the ID token in the process.
    // The session cookie will have the same claims as the ID token.
    String sessionCookie = FirebaseAuth.getInstance().createSessionCookie(idToken, options);
    // Set cookie policy parameters as required.
    NewCookie cookie = new NewCookie("session", sessionCookie /* ... other parameters */);
    return Response.ok().cookie(cookie).build();
  } catch (FirebaseAuthException e) {
    return Response.status(Status.UNAUTHORIZED).entity("Failed to create a session cookie")
        .build();
  }
}

פִּיתוֹן

@app.route('/sessionLogin', methods=['POST'])
def session_login():
    # Get the ID token sent by the client
    id_token = flask.request.json['idToken']
    # Set session expiration to 5 days.
    expires_in = datetime.timedelta(days=5)
    try:
        # Create the session cookie. This will also verify the ID token in the process.
        # The session cookie will have the same claims as the ID token.
        session_cookie = auth.create_session_cookie(id_token, expires_in=expires_in)
        response = flask.jsonify({'status': 'success'})
        # Set cookie policy for session cookie.
        expires = datetime.datetime.now() + expires_in
        response.set_cookie(
            'session', session_cookie, expires=expires, httponly=True, secure=True)
        return response
    except exceptions.FirebaseError:
        return flask.abort(401, 'Failed to create a session cookie')

ללכת

return func(w http.ResponseWriter, r *http.Request) {
	// Get the ID token sent by the client
	defer r.Body.Close()
	idToken, err := getIDTokenFromBody(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Set session expiration to 5 days.
	expiresIn := time.Hour * 24 * 5

	// Create the session cookie. This will also verify the ID token in the process.
	// The session cookie will have the same claims as the ID token.
	// To only allow session cookie setting on recent sign-in, auth_time in ID token
	// can be checked to ensure user was recently signed in before creating a session cookie.
	cookie, err := client.SessionCookie(r.Context(), idToken, expiresIn)
	if err != nil {
		http.Error(w, "Failed to create a session cookie", http.StatusInternalServerError)
		return
	}

	// Set cookie policy for session cookie.
	http.SetCookie(w, &http.Cookie{
		Name:     "session",
		Value:    cookie,
		MaxAge:   int(expiresIn.Seconds()),
		HttpOnly: true,
		Secure:   true,
	})
	w.Write([]byte(`{"status": "success"}`))
}

C #

// POST: /sessionLogin
[HttpPost]
public async Task<ActionResult> Login([FromBody] LoginRequest request)
{
    // Set session expiration to 5 days.
    var options = new SessionCookieOptions()
    {
        ExpiresIn = TimeSpan.FromDays(5),
    };

    try
    {
        // Create the session cookie. This will also verify the ID token in the process.
        // The session cookie will have the same claims as the ID token.
        var sessionCookie = await FirebaseAuth.DefaultInstance
            .CreateSessionCookieAsync(request.IdToken, options);

        // Set cookie policy parameters as required.
        var cookieOptions = new CookieOptions()
        {
            Expires = DateTimeOffset.UtcNow.Add(options.ExpiresIn),
            HttpOnly = true,
            Secure = true,
        };
        this.Response.Cookies.Append("session", sessionCookie, cookieOptions);
        return this.Ok();
    }
    catch (FirebaseAuthException)
    {
        return this.Unauthorized("Failed to create a session cookie");
    }
}

עבור יישומים רגישים, יש לבדוק את auth_time לפני הנפקת קובץ ה- cookie של ההפעלה, ולמזער את חלון ההתקפה במקרה שנגנב אסימון מזהה:

Node.js

admin
  .auth()
  .verifyIdToken(idToken)
  .then((decodedIdToken) => {
    // Only process if the user just signed in in the last 5 minutes.
    if (new Date().getTime() / 1000 - decodedIdToken.auth_time < 5 * 60) {
      // Create session cookie and set it.
      return admin.auth().createSessionCookie(idToken, { expiresIn });
    }
    // A user that was not recently signed in is trying to set a session cookie.
    // To guard against ID token theft, require re-authentication.
    res.status(401).send('Recent sign in required!');
  });

ג'אווה

// To ensure that cookies are set only on recently signed in users, check auth_time in
// ID token before creating a cookie.
FirebaseToken decodedToken = FirebaseAuth.getInstance().verifyIdToken(idToken);
long authTimeMillis = TimeUnit.SECONDS.toMillis(
    (long) decodedToken.getClaims().get("auth_time"));

// Only process if the user signed in within the last 5 minutes.
if (System.currentTimeMillis() - authTimeMillis < TimeUnit.MINUTES.toMillis(5)) {
  long expiresIn = TimeUnit.DAYS.toMillis(5);
  SessionCookieOptions options = SessionCookieOptions.builder()
      .setExpiresIn(expiresIn)
      .build();
  String sessionCookie = FirebaseAuth.getInstance().createSessionCookie(idToken, options);
  // Set cookie policy parameters as required.
  NewCookie cookie = new NewCookie("session", sessionCookie);
  return Response.ok().cookie(cookie).build();
}
// User did not sign in recently. To guard against ID token theft, require
// re-authentication.
return Response.status(Status.UNAUTHORIZED).entity("Recent sign in required").build();

פִּיתוֹן

# To ensure that cookies are set only on recently signed in users, check auth_time in
# ID token before creating a cookie.
try:
    decoded_claims = auth.verify_id_token(id_token)
    # Only process if the user signed in within the last 5 minutes.
    if time.time() - decoded_claims['auth_time'] < 5 * 60:
        expires_in = datetime.timedelta(days=5)
        expires = datetime.datetime.now() + expires_in
        session_cookie = auth.create_session_cookie(id_token, expires_in=expires_in)
        response = flask.jsonify({'status': 'success'})
        response.set_cookie(
            'session', session_cookie, expires=expires, httponly=True, secure=True)
        return response
    # User did not sign in recently. To guard against ID token theft, require
    # re-authentication.
    return flask.abort(401, 'Recent sign in required')
except auth.InvalidIdTokenError:
    return flask.abort(401, 'Invalid ID token')
except exceptions.FirebaseError:
    return flask.abort(401, 'Failed to create a session cookie')

ללכת

return func(w http.ResponseWriter, r *http.Request) {
	// Get the ID token sent by the client
	defer r.Body.Close()
	idToken, err := getIDTokenFromBody(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	decoded, err := client.VerifyIDToken(r.Context(), idToken)
	if err != nil {
		http.Error(w, "Invalid ID token", http.StatusUnauthorized)
		return
	}
	// Return error if the sign-in is older than 5 minutes.
	if time.Now().Unix()-decoded.Claims["auth_time"].(int64) > 5*60 {
		http.Error(w, "Recent sign-in required", http.StatusUnauthorized)
		return
	}

	expiresIn := time.Hour * 24 * 5
	cookie, err := client.SessionCookie(r.Context(), idToken, expiresIn)
	if err != nil {
		http.Error(w, "Failed to create a session cookie", http.StatusInternalServerError)
		return
	}
	http.SetCookie(w, &http.Cookie{
		Name:     "session",
		Value:    cookie,
		MaxAge:   int(expiresIn.Seconds()),
		HttpOnly: true,
		Secure:   true,
	})
	w.Write([]byte(`{"status": "success"}`))
}

C #

// To ensure that cookies are set only on recently signed in users, check auth_time in
// ID token before creating a cookie.
var decodedToken = await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(idToken);
var authTime = new DateTime(1970, 1, 1).AddSeconds(
    (long)decodedToken.Claims["auth_time"]);

// Only process if the user signed in within the last 5 minutes.
if (DateTime.UtcNow - authTime < TimeSpan.FromMinutes(5))
{
    var options = new SessionCookieOptions()
    {
        ExpiresIn = TimeSpan.FromDays(5),
    };
    var sessionCookie = await FirebaseAuth.DefaultInstance.CreateSessionCookieAsync(
        idToken, options);
    // Set cookie policy parameters as required.
    this.Response.Cookies.Append("session", sessionCookie);
    return this.Ok();
}

// User did not sign in recently. To guard against ID token theft, require
// re-authentication.
return this.Unauthorized("Recent sign in required");

לאחר הכניסה, כל החלקים המוגנים על הגישה של האתר צריכים לבדוק את קובץ ה- cookie של ההפעלה ולאמת אותו לפני הגשת תוכן מוגבל על סמך כלל אבטחה.

Node.js

// Whenever a user is accessing restricted content that requires authentication.
app.post('/profile', (req, res) => {
  const sessionCookie = req.cookies.session || '';
  // Verify the session cookie. In this case an additional check is added to detect
  // if the user's Firebase session was revoked, user deleted/disabled, etc.
  admin
    .auth()
    .verifySessionCookie(sessionCookie, true /** checkRevoked */)
    .then((decodedClaims) => {
      serveContentForUser('/profile', req, res, decodedClaims);
    })
    .catch((error) => {
      // Session cookie is unavailable or invalid. Force user to login.
      res.redirect('/login');
    });
});

ג'אווה

@POST
@Path("/profile")
public Response verifySessionCookie(@CookieParam("session") Cookie cookie) {
  String sessionCookie = cookie.getValue();
  try {
    // Verify the session cookie. In this case an additional check is added to detect
    // if the user's Firebase session was revoked, user deleted/disabled, etc.
    final boolean checkRevoked = true;
    FirebaseToken decodedToken = FirebaseAuth.getInstance().verifySessionCookie(
        sessionCookie, checkRevoked);
    return serveContentForUser(decodedToken);
  } catch (FirebaseAuthException e) {
    // Session cookie is unavailable, invalid or revoked. Force user to login.
    return Response.temporaryRedirect(URI.create("/login")).build();
  }
}

פִּיתוֹן

@app.route('/profile', methods=['POST'])
def access_restricted_content():
    session_cookie = flask.request.cookies.get('session')
    if not session_cookie:
        # Session cookie is unavailable. Force user to login.
        return flask.redirect('/login')

    # Verify the session cookie. In this case an additional check is added to detect
    # if the user's Firebase session was revoked, user deleted/disabled, etc.
    try:
        decoded_claims = auth.verify_session_cookie(session_cookie, check_revoked=True)
        return serve_content_for_user(decoded_claims)
    except auth.InvalidSessionCookieError:
        # Session cookie is invalid, expired or revoked. Force user to login.
        return flask.redirect('/login')

ללכת

return func(w http.ResponseWriter, r *http.Request) {
	// Get the ID token sent by the client
	cookie, err := r.Cookie("session")
	if err != nil {
		// Session cookie is unavailable. Force user to login.
		http.Redirect(w, r, "/login", http.StatusFound)
		return
	}

	// Verify the session cookie. In this case an additional check is added to detect
	// if the user's Firebase session was revoked, user deleted/disabled, etc.
	decoded, err := client.VerifySessionCookieAndCheckRevoked(r.Context(), cookie.Value)
	if err != nil {
		// Session cookie is invalid. Force user to login.
		http.Redirect(w, r, "/login", http.StatusFound)
		return
	}

	serveContentForUser(w, r, decoded)
}

C #

// POST: /profile
[HttpPost]
public async Task<ActionResult> Profile()
{
    var sessionCookie = this.Request.Cookies["session"];
    if (string.IsNullOrEmpty(sessionCookie))
    {
        // Session cookie is not available. Force user to login.
        return this.Redirect("/login");
    }

    try
    {
        // Verify the session cookie. In this case an additional check is added to detect
        // if the user's Firebase session was revoked, user deleted/disabled, etc.
        var checkRevoked = true;
        var decodedToken = await FirebaseAuth.DefaultInstance.VerifySessionCookieAsync(
            sessionCookie, checkRevoked);
        return ViewContentForUser(decodedToken);
    }
    catch (FirebaseAuthException)
    {
        // Session cookie is invalid or revoked. Force user to login.
        return this.Redirect("/login");
    }
}

אמת את קובצי ה- cookie של הפעלות באמצעות ממשק ה- API של מנהל ה- SDK לאמת . זוהי פעולה תקורה נמוכה. האישורים הציבוריים נחקרים בתחילה ושומרים אותם במטמון עד לתוקף. ניתן לבצע אימות קובצי cookie של מושב באמצעות האישורים הציבוריים במטמון ללא כל בקשות רשת נוספות.

אם קובץ ה- cookie אינו תקף, ודא שהוא מנוקה ובקש מהמשתמש להיכנס שוב. קיימת אפשרות נוספת לבדיקת ביטול הפעלות. שים לב שהדבר מוסיף בקשת רשת נוספת בכל פעם שעוגיית ה- session מאומתת.

מטעמי אבטחה, לא ניתן להשתמש בעוגיות הפעלה של Firebase עם שירותי Firebase אחרים בגלל תקופת התוקף המותאמת אישית שלהם, שניתן להגדיר למשך מקסימום של שבועיים. כל היישומים המשתמשים בעוגיות בצד השרת צפויים לאכוף בדיקות הרשאות לאחר אימות צד שרת העוגיות הללו.

Node.js

admin
  .auth()
  .verifySessionCookie(sessionCookie, true)
  .then((decodedClaims) => {
    // Check custom claims to confirm user is an admin.
    if (decodedClaims.admin === true) {
      return serveContentForAdmin('/admin', req, res, decodedClaims);
    }
    res.status(401).send('UNAUTHORIZED REQUEST!');
  })
  .catch((error) => {
    // Session cookie is unavailable or invalid. Force user to login.
    res.redirect('/login');
  });

ג'אווה

try {
  final boolean checkRevoked = true;
  FirebaseToken decodedToken = FirebaseAuth.getInstance().verifySessionCookie(
      sessionCookie, checkRevoked);
  if (Boolean.TRUE.equals(decodedToken.getClaims().get("admin"))) {
    return serveContentForAdmin(decodedToken);
  }
  return Response.status(Status.UNAUTHORIZED).entity("Insufficient permissions").build();
} catch (FirebaseAuthException e) {
  // Session cookie is unavailable, invalid or revoked. Force user to login.
  return Response.temporaryRedirect(URI.create("/login")).build();
}

פִּיתוֹן

try:
    decoded_claims = auth.verify_session_cookie(session_cookie, check_revoked=True)
    # Check custom claims to confirm user is an admin.
    if decoded_claims.get('admin') is True:
        return serve_content_for_admin(decoded_claims)

    return flask.abort(401, 'Insufficient permissions')
except auth.InvalidSessionCookieError:
    # Session cookie is invalid, expired or revoked. Force user to login.
    return flask.redirect('/login')

ללכת

return func(w http.ResponseWriter, r *http.Request) {
	cookie, err := r.Cookie("session")
	if err != nil {
		// Session cookie is unavailable. Force user to login.
		http.Redirect(w, r, "/login", http.StatusFound)
		return
	}

	decoded, err := client.VerifySessionCookieAndCheckRevoked(r.Context(), cookie.Value)
	if err != nil {
		// Session cookie is invalid. Force user to login.
		http.Redirect(w, r, "/login", http.StatusFound)
		return
	}

	// Check custom claims to confirm user is an admin.
	if decoded.Claims["admin"] != true {
		http.Error(w, "Insufficient permissions", http.StatusUnauthorized)
		return
	}

	serveContentForAdmin(w, r, decoded)
}

C #

try
{
    var checkRevoked = true;
    var decodedToken = await FirebaseAuth.DefaultInstance.VerifySessionCookieAsync(
        sessionCookie, checkRevoked);
    object isAdmin;
    if (decodedToken.Claims.TryGetValue("admin", out isAdmin) && (bool)isAdmin)
    {
        return ViewContentForAdmin(decodedToken);
    }

    return this.Unauthorized("Insufficient permissions");
}
catch (FirebaseAuthException)
{
    // Session cookie is invalid or revoked. Force user to login.
    return this.Redirect("/login");
}

התנתק

כאשר משתמש מתנתק מצד הלקוח, התמודד עם זה בצד השרת באמצעות נקודת קצה. בקשת POST / GET אמורה לגרום למחיקת קובץ ה- cookie של ההפעלה. שים לב שלמרות שהעוגיה מנוקה, היא נשארת פעילה עד לתום התפוגה הטבעית שלה.

Node.js

app.post('/sessionLogout', (req, res) => {
  res.clearCookie('session');
  res.redirect('/login');
});

ג'אווה

@POST
@Path("/sessionLogout")
public Response clearSessionCookie(@CookieParam("session") Cookie cookie) {
  final int maxAge = 0;
  NewCookie newCookie = new NewCookie(cookie, null, maxAge, true);
  return Response.temporaryRedirect(URI.create("/login")).cookie(newCookie).build();
}

פִּיתוֹן

@app.route('/sessionLogout', methods=['POST'])
def session_logout():
    response = flask.make_response(flask.redirect('/login'))
    response.set_cookie('session', expires=0)
    return response

ללכת

return func(w http.ResponseWriter, r *http.Request) {
	http.SetCookie(w, &http.Cookie{
		Name:   "session",
		Value:  "",
		MaxAge: 0,
	})
	http.Redirect(w, r, "/login", http.StatusFound)
}

C #

// POST: /sessionLogout
[HttpPost]
public ActionResult ClearSessionCookie()
{
    this.Response.Cookies.Delete("session");
    return this.Redirect("/login");
}

קריאה ל- API לביטול מבטלת את ההפעלה וגם מבטלת את כל ההפעלות האחרות של המשתמש, מה שמאלץ כניסה חדשה. עבור יישומים רגישים, מומלץ למשך זמן קצר יותר.

Node.js

app.post('/sessionLogout', (req, res) => {
  const sessionCookie = req.cookies.session || '';
  res.clearCookie('session');
  admin
    .auth()
    .verifySessionCookie(sessionCookie)
    .then((decodedClaims) => {
      return admin.auth().revokeRefreshTokens(decodedClaims.sub);
    })
    .then(() => {
      res.redirect('/login');
    })
    .catch((error) => {
      res.redirect('/login');
    });
});

ג'אווה

@POST
@Path("/sessionLogout")
public Response clearSessionCookieAndRevoke(@CookieParam("session") Cookie cookie) {
  String sessionCookie = cookie.getValue();
  try {
    FirebaseToken decodedToken = FirebaseAuth.getInstance().verifySessionCookie(sessionCookie);
    FirebaseAuth.getInstance().revokeRefreshTokens(decodedToken.getUid());
    final int maxAge = 0;
    NewCookie newCookie = new NewCookie(cookie, null, maxAge, true);
    return Response.temporaryRedirect(URI.create("/login")).cookie(newCookie).build();
  } catch (FirebaseAuthException e) {
    return Response.temporaryRedirect(URI.create("/login")).build();
  }
}

פִּיתוֹן

@app.route('/sessionLogout', methods=['POST'])
def session_logout():
    session_cookie = flask.request.cookies.get('session')
    try:
        decoded_claims = auth.verify_session_cookie(session_cookie)
        auth.revoke_refresh_tokens(decoded_claims['sub'])
        response = flask.make_response(flask.redirect('/login'))
        response.set_cookie('session', expires=0)
        return response
    except auth.InvalidSessionCookieError:
        return flask.redirect('/login')

ללכת

return func(w http.ResponseWriter, r *http.Request) {
	cookie, err := r.Cookie("session")
	if err != nil {
		// Session cookie is unavailable. Force user to login.
		http.Redirect(w, r, "/login", http.StatusFound)
		return
	}

	decoded, err := client.VerifySessionCookie(r.Context(), cookie.Value)
	if err != nil {
		// Session cookie is invalid. Force user to login.
		http.Redirect(w, r, "/login", http.StatusFound)
		return
	}
	if err := client.RevokeRefreshTokens(r.Context(), decoded.UID); err != nil {
		http.Error(w, "Failed to revoke refresh token", http.StatusInternalServerError)
		return
	}

	http.SetCookie(w, &http.Cookie{
		Name:   "session",
		Value:  "",
		MaxAge: 0,
	})
	http.Redirect(w, r, "/login", http.StatusFound)
}

C #

// POST: /sessionLogout
[HttpPost]
public async Task<ActionResult> ClearSessionCookieAndRevoke()
{
    var sessionCookie = this.Request.Cookies["session"];
    try
    {
        var decodedToken = await FirebaseAuth.DefaultInstance
            .VerifySessionCookieAsync(sessionCookie);
        await FirebaseAuth.DefaultInstance.RevokeRefreshTokensAsync(decodedToken.Uid);
        this.Response.Cookies.Delete("session");
        return this.Redirect("/login");
    }
    catch (FirebaseAuthException)
    {
        return this.Redirect("/login");
    }
}

אמת את עוגיות ההפעלה באמצעות ספריית JWT של צד שלישי

אם ה- backend שלך נמצא בשפה שאינה נתמכת על ידי Firkase AdKin SDK, אתה עדיין יכול לאמת קובצי Cookie של הפעלות. ראשית, מצא ספריית JWT של צד שלישי עבור השפה שלך . לאחר מכן, ודא את הכותרת, המטען והחתימה של קובץ ה- cookie של ההפעלה.

ודא שכותרת קובץ ה- cookie של ההפעלה תואמת את האילוצים הבאים:

תביעות כותרת העוגיות של מושב Firebase
alg אַלגוֹרִיתְם "RS256"
kid מזהה מפתח חייב להתאים לאחד המפתחות הציבוריים המפורטים בכתובת https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys

ודא שהמטען של קובץ ה- cookie של ההפעלה תואם לאילוצים הבאים:

תביעות מטען לעוגיות מושב Firebase
exp תאריך תפוגה חייב להיות בעתיד. הזמן נמדד בשניות מאז תקופת UNIX. התפוגה מוגדרת על סמך משך הזמן המותאם אישית שסופק בעת יצירת קובץ ה- cookie.
iat הונפק בזמן חייב להיות בעבר. הזמן נמדד בשניות מאז תקופת UNIX.
aud קהל חייב להיות מזהה פרויקט Firebase שלך, המזהה הייחודי לפרויקט Firebase שלך, אשר נמצא בכתובת ה- URL של המסוף של אותו פרויקט.
iss מנפיק חייב להיות "https://session.firebase.google.com/<projectId>" ", כאשר <projectId> הוא אותו מזהה פרויקט ששימש ל- aud לעיל.
sub נושא חייב להיות מחרוזת שאיננו ריקה חייב להיות uid של המשתמש או המכשיר.
auth_time זמן אימות חייב להיות בעבר. הזמן בו המשתמש אימת. זה תואם את זמן auth_time של אסימון המזהה המשמש ליצירת קובץ ה- cookie של ההפעלה.

לסיום, וודא כי קובץ ה- cookie של ההפעלה נחתם על ידי המפתח הפרטי המתאים לתביעת הילד של האסימון. השג את המפתח הציבורי מ https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys והשתמש בספריית JWT כדי לאמת את החתימה. השתמש בערך max-age בכותרת Cache-Control של התגובה מאותה נקודת קצה כדי לקבוע מתי לרענן את המפתחות הציבוריים.

אם כל האימותים הנ"ל מוצלחים, תוכל להשתמש בנושא ( sub ) של קובץ ה- cookie כ- UID של המשתמש או המכשיר המתאימים.