Firebase Auth обеспечивает управление сеансовыми cookie-файлами на стороне сервера для традиционных веб-сайтов, которые полагаются на сеансовые cookie-файлы. Это решение имеет несколько преимуществ по сравнению с клиентскими краткосрочными ID-токенами, которые могут требовать механизма перенаправления каждый раз для обновления сеансового cookie-файла по истечении срока действия:
- Повышенная безопасность за счет сеансовых токенов на основе JWT, которые можно генерировать только с использованием авторизованных учетных записей служб.
- Файлы cookie сеанса без сохранения состояния, которые обладают всеми преимуществами использования JWT для аутентификации. Файл cookie сеанса имеет те же самые утверждения (включая пользовательские утверждения), что и токен ID, что делает те же проверки разрешений применимыми к файлам cookie сеанса.
- Возможность создания сеансовых cookie-файлов с настраиваемым сроком действия от 5 минут до 2 недель.
- Гибкость в применении политик использования cookie-файлов на основе требований приложения: домен, путь, безопасность,
httpOnly
и т. д. - Возможность отзыва сеансовых cookie-файлов при подозрении на кражу токена с использованием существующего API отзыва токенов обновления.
- Возможность обнаружения отмены сеанса при значительных изменениях в учетной записи.
Войти
Предполагая, что приложение использует httpOnly
серверные файлы cookie, войдите в систему пользователя на странице входа с помощью клиентских SDK. Генерируется токен Firebase ID, который затем отправляется через HTTP POST в конечную точку входа сеанса, где с помощью Admin SDK генерируется файл 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
Для генерации сеансового cookie в обмен на предоставленный токен ID требуется конечная точка HTTP. Отправьте токен на конечную точку, установив пользовательское время продолжительности сеанса с помощью Firebase Admin SDK. Следует принять соответствующие меры для предотвращения атак с подделкой межсайтовых запросов (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.
getAuth()
.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"}`))
}
С#
// 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-файла, чтобы минимизировать окно атаки в случае кражи токена ID:
Node.js
getAuth()
.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 getAuth().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"}`))
}
С#
// 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-файлы и разрешения
После входа в систему все защищенные разделы веб-сайта должны проверять сеансовые 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.
getAuth()
.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)
}
С#
// 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");
}
}
Проверка сеансовых куки с помощью API Admin SDK verifySessionCookie . Это операция с низкими накладными расходами. Публичные сертификаты изначально запрашиваются и кэшируются до истечения срока их действия. Проверка сеансовых куки может быть выполнена с кэшированными публичными сертификатами без дополнительных сетевых запросов.
Если файл cookie недействителен, убедитесь, что он очищен, и попросите пользователя снова войти в систему. Доступна дополнительная опция для проверки отзыва сеанса. Обратите внимание, что это добавляет дополнительный сетевой запрос каждый раз, когда проверяется файл cookie сеанса.
По соображениям безопасности сеансовые файлы cookie Firebase не могут использоваться с другими службами Firebase из-за их настраиваемого срока действия, который может быть установлен на максимальную продолжительность в 2 недели. Все приложения, использующие файлы cookie на стороне сервера, должны принудительно проверять разрешения после проверки этих файлов cookie на стороне сервера.
Node.js
getAuth()
.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)
}
С#
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. Обратите внимание, что даже если 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)
}
С#
// 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');
getAuth()
.verifySessionCookie(sessionCookie)
.then((decodedClaims) => {
return getAuth().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)
}
С#
// 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");
}
}
Проверка сеансовых cookie-файлов с использованием сторонней библиотеки JWT
Если ваш бэкенд на языке, который не поддерживается Firebase Admin SDK, вы все равно можете проверить сеансовые куки. Сначала найдите стороннюю библиотеку JWT для вашего языка . Затем проверьте заголовок, полезную нагрузку и подпись сеансового куки.
Убедитесь, что заголовок сеансового cookie-файла соответствует следующим ограничениям:
Утверждения заголовка cookie-файла сеанса Firebase | ||
---|---|---|
alg | Алгоритм | "RS256" |
kid | Идентификатор ключа | Должен соответствовать одному из открытых ключей, перечисленных на https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys |
Убедитесь, что полезная нагрузка сеансового cookie-файла соответствует следующим ограничениям:
Заявления о полезной нагрузке файлов 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 токена ID, использованного для создания сеансового cookie. |
Наконец, убедитесь, что сеансовый cookie был подписан закрытым ключом, соответствующим заявлению токена kid. Получите открытый ключ с https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys
и используйте библиотеку JWT для проверки подписи. Используйте значение max-age в заголовке Cache-Control
ответа от этой конечной точки, чтобы определить, когда обновлять открытые ключи.
Если все вышеуказанные проверки пройдены успешно, вы можете использовать тему ( sub
) сеансового cookie-файла в качестве uid соответствующего пользователя или устройства.