This commit is contained in:
2025-04-01 11:52:46 +02:00
parent f1586abc86
commit c8c30d3838
7 changed files with 270 additions and 122 deletions
@@ -1,79 +1,12 @@
import "dart:convert";
typedef JwtPayload = Map<String, dynamic>;
/// An extension on `String` to extract useful information from JSON Web Tokens (JWT).
///
/// This extension provides methods to decode a JWT string and retrieve common
/// fields like email, expiration time, and user ID.
extension JWTUtility on String {
/// Extracts the email from the JWT payload.
///
/// This method attempts to parse the JWT and retrieve the `sub` field, which is
/// typically used to store the email of the token owner.
///
/// Returns the email as a `String` if present, or `null` if the parsing fails or the
/// email is not found.
///
/// Example:
/// ```dart
/// String token = "your.jwt.token";
/// String? email = token.jwtEmail();
/// ```
String? jwtEmail() {
try {
final payload = _parseJwt(this);
final String email = payload["sub"] as String;
return email;
} catch (_) {
return null;
}
}
/// Extracts the expiration time from the JWT payload.
///
/// This method retrieves the `exp` field from the JWT, which represents the expiration
/// time as a Unix timestamp. The timestamp is converted to a `DateTime` object.
///
/// Returns the `DateTime` representing the expiration time, or `null` if the parsing
/// fails or the expiration time is not found.
///
/// Example:
/// ```dart
/// String token = "your.jwt.token";
/// DateTime? expiry = token.jwtExpiryTime();
/// ```
DateTime? jwtExpiryTime() {
try {
final payload = _parseJwt(this);
final expiry = payload["exp"] as int;
final date = DateTime.fromMillisecondsSinceEpoch(expiry * 1000);
return date;
} catch (_) {
return null;
}
}
/// Extracts the user ID from the JWT payload.
///
/// This method retrieves the `uid` field, which is typically the unique user identifier.
/// This ID can be used in analytics or for tracking purposes.
///
/// Returns the user ID as a `String`, or `null` if the parsing fails or the ID is not found.
///
/// Example:
/// ```dart
/// String token = "your.jwt.token";
/// String? userId = token.jwtUserId();
/// ```
String? jwtUserId() {
try {
final payload = _parseJwt(this);
final String id = payload["uid"] as String;
return id;
} catch (_) {
return null;
}
}
/// Decodes a base64 URL-encoded string.
///
/// This method replaces the URL-safe characters in the base64 string (`-` and `_`)
@@ -111,20 +44,132 @@ extension JWTUtility on String {
///
/// Example:
/// ```dart
/// Map<String, dynamic> payload = _parseJwt("your.jwt.token");
/// Map<String, dynamic> payload = parseJwt("your.jwt.token");
/// ```
Map<String, dynamic> _parseJwt(String token) {
final parts = token.split(".");
JwtPayload get jwt {
final parts = this.split(".");
if (parts.length != 3) {
throw Exception("invalid token");
throw InvalidTokenException();
}
final payload = _decodeBase64(parts[1]);
final dynamic payloadMap = json.decode(payload);
if (payloadMap is! Map<String, dynamic>) {
throw Exception("invalid payload");
final payloadMap = json.decode(payload) as JwtPayload?;
if (payloadMap is! JwtPayload) {
throw InvalidPayloadException();
}
return payloadMap;
}
}
extension JWTMapUtility on JwtPayload {
/// Extracts the email from the JWT payload.
///
/// This method attempts to parse the JWT and retrieve the `sub` field, which is
/// typically used to store the email of the token owner.
///
/// Returns the email as a `String` if present, or `null` if the parsing fails or the
/// email is not found.
///
/// Example:
/// ```dart
/// String token = "your.jwt.token";
/// String? email = token.jwt.email;
/// ```
String? get email {
try {
return this["sub"] as String;
} catch (_) {
return null;
}
}
/// Extracts the given (first) name from the JWT payload.
///
/// This method attempts to parse the JWT and retrieve the `given_name` field,
/// which is typically used to store the given (first) name of the token owner.
///
/// Returns the given name as a `String` if present, or `null` if the parsing
/// fails or the given name is not found.
///
/// Example:
/// ```dart
/// String token = "your.jwt.token";
/// String? givenName = token.jwt.givenName;
/// ```
String? get givenName {
try {
return this["given_name"] as String;
} catch (_) {
return null;
}
}
/// Extracts the family (last) name from the JWT payload.
///
/// This method attempts to parse the JWT and retrieve the `family_name` field,
/// which is typically used to store the family (last) name of the token owner.
///
/// Returns the family name as a `String` if present, or `null` if the parsing
/// fails or the family name is not found.
///
/// Example:
/// ```dart
/// String token = "your.jwt.token";
/// String? familyName = token.jwt.familyName;
/// ```
String? get familyName {
try {
return this["family_name"] as String;
} catch (_) {
return null;
}
}
/// Extracts the expiration time from the JWT payload.
///
/// This method retrieves the `exp` field from the JWT, which represents the expiration
/// time as a Unix timestamp. The timestamp is converted to a `DateTime` object.
///
/// Returns the `DateTime` representing the expiration time, or `null` if the parsing
/// fails or the expiration time is not found.
///
/// Example:
/// ```dart
/// String token = "your.jwt.token";
/// DateTime? expiry = token.jwt.expiryTime;
/// ```
DateTime? get expiryTime {
try {
final expiry = this["exp"] as int;
final date = DateTime.fromMillisecondsSinceEpoch(expiry * 1000);
return date;
} catch (_) {
return null;
}
}
/// Extracts the user ID from the JWT payload.
///
/// This method retrieves the `uid` field, which is typically the unique user identifier.
/// This ID can be used in analytics or for tracking purposes.
///
/// Returns the user ID as a `String`, or `null` if the parsing fails or the ID is not found.
///
/// Example:
/// ```dart
/// String token = "your.jwt.token";
/// String? userId = token.jwt.userId;
/// ```
String? get userId {
try {
return this["uid"] as String;
} catch (_) {
return null;
}
}
}
class InvalidTokenException implements Exception {}
class InvalidPayloadException implements Exception {}