feat(security): add refresh token capability to API (#52)
## Add backend refresh tokens
Adds rotating server-side refresh tokens so the access token can be short-lived (5m) without forcing frequent re-login.
- New `POST /api/v1/users/refresh` exchanges the `refreshToken` cookie for a new refresh token and JWT
- Each login starts a token family; reusing a used token after the 5s grace period revokes the whole family
- Logout revokes the family; an hourly job deletes dead families
- Google ID token verification extracted into `GoogleVerifierService`; config moved to a validated `AuthProperties`
- Unauthenticated requests now return 401 instead of 403
- Migration `V2__refresh_tokens.sql` adds `token_families` and `refresh_tokens`
**Breaking changes**
- Cookie `token` renamed to `accessToken` (existing sessions are logged out)
- `/login` and `/refresh` no longer return the JWT in the body, only `{ accessTokenExpiresIn }`
- `jwt.secret.key` / `jwt.expiration` replaced by `app.security.*`; `JWT_SECRET_KEY` must be 32+ chars
- Frontend must call `/refresh` on 401 or before the access token expires
Reviewed-on: #52
This commit was merged in pull request #52.
This commit is contained in:
31
src/main/java/com/ddf/vodsystem/entities/TokenFamily.java
Normal file
31
src/main/java/com/ddf/vodsystem/entities/TokenFamily.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package com.ddf.vodsystem.entities;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Entity
|
||||
@Table(name = "token_families")
|
||||
@Data
|
||||
public class TokenFamily {
|
||||
@Id
|
||||
@Column(name = "id", nullable = false, unique = true)
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "user_id", nullable = false)
|
||||
private User user;
|
||||
|
||||
@Column(name = "created_at", nullable = false)
|
||||
@CreationTimestamp
|
||||
private Instant createdAt;
|
||||
|
||||
@Column(name = "expires_at", nullable = false)
|
||||
private Instant expiresAt;
|
||||
|
||||
@Column(name = "revoked_at")
|
||||
private Instant revokedAt;
|
||||
}
|
||||
Reference in New Issue
Block a user