This is an automated email from the ASF dual-hosted git repository.
linxinyuan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git
The following commit(s) were added to refs/heads/main by this push:
new f90848e557 feat(auth): removed token refresh functionality (#3765)
f90848e557 is described below
commit f90848e5572c46e944e4a655d70a0dfd1be1333a
Author: Victor Fawole <[email protected]>
AuthorDate: Wed Sep 24 22:52:14 2025 -0400
feat(auth): removed token refresh functionality (#3765)
## Description
---
This PR mitigates the security issue described in #3737, by removing the
token refresh functionality.
## Problem
---
When user's sign in, they receive a new token. This token has a TTL of 2
days (2880 minutes), as defined by `expiration-in-minutes` in
`auth.conf`. However, a user's token is refreshed if they make any
action that creates a request to the backend, if the token has not
already expired. The refresh time is the same as the original TTL, thus,
a user could theoretically be signed in indefinitely. From a security
perspective this is unsafe.
## Solution
---
The token refresh functionality was removed from `auth.service.ts`.
Additionally, since the `refreshToken` in `auth.service.ts` called the
`/refresh` route from the backend, the route and any classes/functions
it used were removed (`AuthResource.scala`,
`RefreshTokenRequest.scala`). The TTL of the token was then changed to 7
days (10080 minutes) to improve user experience.
## Side Effects
---
As noted in #3738, when a user's token is expired, but are not logged
out, they are still able to access some data, but are unable to make any
changes.
Because tokens are no longer refreshed, the user is more likely to
encounter this case.
Fixes #3737
---
.../http/request/auth/RefreshTokenRequest.scala | 22 --------------
.../texera/web/resource/auth/AuthResource.scala | 21 ++-----------
core/config/src/main/resources/auth.conf | 2 +-
.../src/app/common/service/user/auth.service.ts | 34 ----------------------
4 files changed, 3 insertions(+), 76 deletions(-)
diff --git
a/core/amber/src/main/scala/edu/uci/ics/texera/web/model/http/request/auth/RefreshTokenRequest.scala
b/core/amber/src/main/scala/edu/uci/ics/texera/web/model/http/request/auth/RefreshTokenRequest.scala
deleted file mode 100644
index 521073afa9..0000000000
---
a/core/amber/src/main/scala/edu/uci/ics/texera/web/model/http/request/auth/RefreshTokenRequest.scala
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package edu.uci.ics.texera.web.model.http.request.auth
-
-case class RefreshTokenRequest(accessToken: String)
diff --git
a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/auth/AuthResource.scala
b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/auth/AuthResource.scala
index 272886e654..ccccdd768a 100644
---
a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/auth/AuthResource.scala
+++
b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/auth/AuthResource.scala
@@ -19,19 +19,10 @@
package edu.uci.ics.texera.web.resource.auth
-import edu.uci.ics.texera.auth.JwtAuth.{
- TOKEN_EXPIRE_TIME_IN_MINUTES,
- jwtClaims,
- jwtConsumer,
- jwtToken
-}
+import edu.uci.ics.texera.auth.JwtAuth.{TOKEN_EXPIRE_TIME_IN_MINUTES,
jwtClaims, jwtToken}
import edu.uci.ics.texera.config.UserSystemConfig
import edu.uci.ics.texera.dao.SqlServer
-import edu.uci.ics.texera.web.model.http.request.auth.{
- RefreshTokenRequest,
- UserLoginRequest,
- UserRegistrationRequest
-}
+import edu.uci.ics.texera.web.model.http.request.auth.{UserLoginRequest,
UserRegistrationRequest}
import edu.uci.ics.texera.web.model.http.response.TokenIssueResponse
import edu.uci.ics.texera.dao.jooq.generated.Tables.USER
import edu.uci.ics.texera.dao.jooq.generated.enums.UserRoleEnum
@@ -107,14 +98,6 @@ class AuthResource {
}
}
- @POST
- @Path("/refresh")
- def refresh(request: RefreshTokenRequest): TokenIssueResponse = {
- val claims = jwtConsumer.process(request.accessToken).getJwtClaims
-
claims.setExpirationTimeMinutesInTheFuture(TOKEN_EXPIRE_TIME_IN_MINUTES.toFloat)
- TokenIssueResponse(jwtToken(claims))
- }
-
@POST
@Path("/register")
def register(request: UserRegistrationRequest): TokenIssueResponse = {
diff --git a/core/config/src/main/resources/auth.conf
b/core/config/src/main/resources/auth.conf
index ef82fc8ace..c99db10c85 100644
--- a/core/config/src/main/resources/auth.conf
+++ b/core/config/src/main/resources/auth.conf
@@ -19,7 +19,7 @@
# Configuration for JWT Authentication. Currently it is used by the
FileService to parse the given JWT Token
auth {
jwt {
- expiration-in-minutes = 2880
+ expiration-in-minutes = 10080
expiration-in-minutes = ${?AUTH_JWT_EXPIRATION_IN_MINUTES}
256-bit-secret = "8a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d"
diff --git a/core/gui/src/app/common/service/user/auth.service.ts
b/core/gui/src/app/common/service/user/auth.service.ts
index 57f90658de..2f47036712 100644
--- a/core/gui/src/app/common/service/user/auth.service.ts
+++ b/core/gui/src/app/common/service/user/auth.service.ts
@@ -48,7 +48,6 @@ export class AuthService {
public static readonly GOOGLE_LOGIN_ENDPOINT = "auth/google/login";
private tokenExpirationSubscription?: Subscription;
- private refreshTokenSubscription?: Subscription;
constructor(
private http: HttpClient,
@@ -112,7 +111,6 @@ export class AuthService {
public logout(): undefined {
AuthService.removeAccessToken();
this.tokenExpirationSubscription?.unsubscribe();
- this.refreshTokenSubscription?.unsubscribe();
return undefined;
}
@@ -145,7 +143,6 @@ export class AuthService {
}
this.registerAutoLogout();
- this.registerAutoRefreshToken();
return {
uid: this.jwtHelperService.decodeToken(token).userId,
name: this.jwtHelperService.decodeToken(token).sub,
@@ -157,37 +154,6 @@ export class AuthService {
};
}
- /**
- * Refreshes the current accessToken to get a new accessToken
- * // TODO: for better security, use a separate refresh token to perform
this refresh
- */
- private refreshToken(): Observable<Readonly<{ accessToken: string }>> {
- return this.http.post<Readonly<{ accessToken: string }>>(
- `${AppSettings.getApiEndpoint()}/${AuthService.REFRESH_TOKEN}`,
- { accessToken: AuthService.getAccessToken() }
- );
- }
-
- private registerAutoRefreshToken() {
- this.refreshTokenSubscription?.unsubscribe();
- const TOKEN_REFRESH_INTERVAL_IN_MIN =
this.config.env.expirationTimeInMinutes - 1;
- // Token Refresh Interval set to Token Expiration Time - 1
- this.refreshTokenSubscription = interval(TOKEN_REFRESH_INTERVAL_IN_MIN *
60 * 1000)
- .pipe(startWith(0)) // to trigger immediately for the first time.
- .subscribe(() => {
- this.refreshToken().subscribe(
- ({ accessToken }) => {
- AuthService.setAccessToken(accessToken);
- this.registerAutoLogout();
- },
- (_: unknown) => {
- // failed to refresh the access token, logout instantly.
- this.logout();
- }
- );
- });
- }
-
private registerAutoLogout() {
this.tokenExpirationSubscription?.unsubscribe();
const expirationTime =
this.jwtHelperService.getTokenExpirationDate()?.getTime();