Passa al contenuto principale

JWT Authentication

Detailed documentation on how JWT (JSON Web Token) authentication works in the Ever Gauzy platform.

How JWT Worksโ€‹

Token Structureโ€‹

A Gauzy JWT access token contains:

{
"id": "user-uuid",
"email": "user@example.com",
"tenantId": "tenant-uuid",
"employeeId": "employee-uuid",
"role": "ADMIN",
"iat": 1704067200,
"exp": 1704153600
}

Claimsโ€‹

ClaimDescription
idUser ID
emailUser email
tenantIdUser's tenant ID
employeeIdAssociated employee ID (if applicable)
roleUser's role name
iatIssued at (Unix timestamp)
expExpiry (Unix timestamp)

Configurationโ€‹

Environment Variablesโ€‹

# JWT secret for signing access tokens
JWT_SECRET=your-very-secure-secret-key

# Access token expiration in seconds (default: 24 hours)
JWT_TOKEN_EXPIRATION_TIME=86400

# Refresh token secret
JWT_REFRESH_TOKEN_SECRET=your-refresh-token-secret

# Refresh token expiration in seconds (default: 7 days)
JWT_REFRESH_TOKEN_EXPIRATION_TIME=604800
warning

Always use strong, unique secrets in production. Never commit secrets to version control.

Token Lifecycleโ€‹

1. Obtain Tokensโ€‹

# Login request
POST /api/auth/login
Content-Type: application/json

{
"email": "admin@ever.co",
"password": "admin"
}

Response:

{
"token": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "eyJhbGciOiJIUzI1NiIs...",
"user": { ... }
}

2. Use Access Tokenโ€‹

Include the access token in Authorization header:

GET /api/employee
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

3. Refresh Tokenโ€‹

When the access token expires, use the refresh token to get a new pair:

POST /api/auth/refresh-token
Content-Type: application/json

{
"refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

Response:

{
"token": "new-access-token",
"refreshToken": "new-refresh-token"
}

4. Token Expiry Flowโ€‹

Passport Strategyโ€‹

The JWT strategy validates tokens on every authenticated request:

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(
private readonly configService: ConfigService,
private readonly userService: UserService,
) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: configService.get("JWT_SECRET"),
});
}

async validate(payload: JwtPayload): Promise<IUser> {
const { id, tenantId } = payload;
const user = await this.userService.findOneById(id);
if (!user) throw new UnauthorizedException();
return user;
}
}

Token Storageโ€‹

Web Applicationโ€‹

Tokens are stored in:

  • Local Storage โ€” persists across browser sessions
  • Session Storage โ€” cleared when browser is closed

Desktop Applicationโ€‹

Tokens are stored using:

  • Electron Store โ€” secure, encrypted local storage
  • Keychain/Credential Manager โ€” OS-level secure storage

Best Practicesโ€‹

ApproachSecurityUX
Local Storageโš ๏ธ XSS vulnerableโœ… Persistent sessions
Session Storageโœ… Session-scopedโš ๏ธ Lost on close
HTTP-Only Cookiesโœ… XSS protectedโœ… Automatic
Electron Storeโœ… Encryptedโœ… Native

Error Responsesโ€‹

ErrorStatusDescription
Missing token401No Authorization header
Invalid token401Token signature invalid
Expired token401Token past exp time
User not found401Token user deleted/disabled
Refresh token expired401Must re-authenticate