refreshToken method

  1. @override
Future<AuthResponse> refreshToken(
  1. String refreshToken
)
override

Refreshes an access token

refreshToken The refresh token Returns new authentication response

Implementation

@override
Future<AuthResponse> refreshToken(String refreshToken) async {
  // Extract session ID and raw token from the combined refresh token
  final parts = refreshToken.split('::');
  if (parts.length != 2) {
    throw AuthException('Invalid refresh token format');
  }
  final sessionId = parts[0];

  // For JWT, verify the refresh token from database
  final tokenRecord = await _tokenService.findToken(refreshToken);

  if (tokenRecord == null) {
    throw AuthException('Invalid refresh token');
  }

  final tokenType = tokenRecord['type'] as String?;
  if (tokenType != 'refresh') {
    throw AuthException('Invalid token type for refresh');
  }

  // Check expiry
  final expiry = _parseDateTime(tokenRecord['expires_at']);
  if (expiry != null) {
    if (DateTime.now().isAfter(expiry)) {
      await _tokenService.deleteToken(refreshToken);
      throw AuthException('Refresh token has expired');
    }
  }

  final userId = tokenRecord['tokenable_id'];

  // Get user data from database
  final provider = _config.getProvider(_providerKey);
  final table = provider['table'] as String;
  final primaryKey = provider['primary_key'] as String;

  // For user retrieval, we still need repository access
  // This could be improved with a UserService interface
  final repository = DatabaseAuthRepository();
  final userData = await repository.findUserById(userId, table, primaryKey);
  if (userData == null) {
    throw AuthException('User not found');
  }

  final user = DatabaseAuthenticatable.fromProviderConfig(
    userData,
    provider,
  );

  // Generate new access token reusing the same session ID
  final now = DateTime.now();
  final payload = {
    'sub': userId,
    'iat': now.millisecondsSinceEpoch ~/ 1000,
    'exp': now.add(_accessTokenExpiry).millisecondsSinceEpoch ~/ 1000,
    'jti': sessionId, // Reuse the same session ID
    'user': _sanitizeUserData(user.toAuthArray()),
  };
  final jwt = JWT(payload);
  final newAccessToken = jwt.sign(SecretKey(_secret));

  // Generate new refresh token with the same session ID
  final rawRefreshToken = _tokenGenerator.generateToken();
  final newRefreshToken = '$sessionId::$rawRefreshToken';

  // Store new refresh token
  final refreshTokenData = {
    'token': newRefreshToken,
    'tokenable_id': userId,
    'guard': _providerKey,
    'type': 'refresh',
    'created_at': DateTime.now().toIso8601String(),
    'expires_at': DateTime.now().add(_refreshTokenExpiry).toIso8601String(),
  };

  await _tokenService.storeToken(refreshTokenData);

  // Clean up old refresh token
  await _tokenService.deleteToken(refreshToken);

  return AuthResponse(
    user: user.toAuthArray(),
    accessToken: newAccessToken,
    refreshToken: newRefreshToken,
    expiresIn: _accessTokenExpiry.inSeconds,
    refreshExpiresIn: _refreshTokenExpiry.inSeconds,
  );
}