mirror of
https://github.com/hanskokx/arcane_helper_utils.git
synced 2026-05-14 02:19:09 +02:00
v1.4.0
This commit is contained in:
@@ -1,3 +1,41 @@
|
|||||||
|
## 1.4.0
|
||||||
|
|
||||||
|
- [BREAKING] JWT-related extensions have been reworked.
|
||||||
|
|
||||||
|
Old:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
String token = "your.jwt.token";
|
||||||
|
DateTime? expiry = token.jwtExpiryTime();
|
||||||
|
String? userId = token.jwtUserId();
|
||||||
|
String? email = token.jwtEmail();
|
||||||
|
```
|
||||||
|
|
||||||
|
New:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
String token = "your.jwt.token";
|
||||||
|
DateTime? expiry = token.jwt.expiryTime;
|
||||||
|
String? userId = token.jwt.userId;
|
||||||
|
String? email = token.jwt.email;
|
||||||
|
|
||||||
|
// Added:
|
||||||
|
JwtPayload? token.jwt;
|
||||||
|
String? givenName = token.jwt.givenName;
|
||||||
|
String? familyName = token.jwt.familyName;
|
||||||
|
```
|
||||||
|
|
||||||
|
Additionally, the exceptions thrown when parsing an invalid JWT have been
|
||||||
|
updated.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
String email = "invalid".jwtEmail() // Previously threw Exception("invalid token")
|
||||||
|
String email = "invalid".jwt.email // Now throws InvalidTokenException()
|
||||||
|
|
||||||
|
String email = "".jwtEmail() // Previously threw Exception("invalid payload")
|
||||||
|
String email = "".jwt.email // Now throws InvalidPayloadException()
|
||||||
|
```
|
||||||
|
|
||||||
## 1.3.2
|
## 1.3.2
|
||||||
|
|
||||||
- Added `isEmptyOrNull` and `isNotEmptyOrNull` extensions for `List` and `String` objects. These extensions are identical to `isNullOrEmpty` and `isNotNullOrEmpty`, respectively.
|
- Added `isEmptyOrNull` and `isNotEmptyOrNull` extensions for `List` and `String` objects. These extensions are identical to `isNullOrEmpty` and `isNotNullOrEmpty`, respectively.
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ providing utility functions and extensions that simplify common tasks.
|
|||||||
- **DateTime Extensions**: Adds additional functionality to the `DateTime`
|
- **DateTime Extensions**: Adds additional functionality to the `DateTime`
|
||||||
class, making it easier to format dates and calculate differences.
|
class, making it easier to format dates and calculate differences.
|
||||||
- **String Extensions**: Enhances the `String` class by adding new methods for
|
- **String Extensions**: Enhances the `String` class by adding new methods for
|
||||||
common transformations and checks, including JWT parsing.
|
common transformations and checks.
|
||||||
|
- **JWT Utilities**: Provides getters to parse a JWT token from a `String`, then
|
||||||
|
get common properties from it.
|
||||||
- **List Extensions**: Adds a new `unique` operator for filtering `List` items.
|
- **List Extensions**: Adds a new `unique` operator for filtering `List` items.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
@@ -260,11 +262,18 @@ making it easier to handle JSON Web Tokens directly as `String` objects.
|
|||||||
|
|
||||||
Here are some examples of how these methods can be utilized:
|
Here are some examples of how these methods can be utilized:
|
||||||
|
|
||||||
|
- Parse a JWT string
|
||||||
|
|
||||||
|
```dart
|
||||||
|
String token = "your.jwt.token";
|
||||||
|
final JwtPayload? payload = token.jwt; // Returns the JWT's payload
|
||||||
|
```
|
||||||
|
|
||||||
- Extracting the email address (`jwt["sub"]`)
|
- Extracting the email address (`jwt["sub"]`)
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
String jwt = "your.jwt.token";
|
String jwt = "your.jwt.token";
|
||||||
final String? email = jwt.jwtEmail(); // Returns the email address in the JWT
|
final String? email = jwt.jwt.email; // Returns the email address in the JWT
|
||||||
```
|
```
|
||||||
|
|
||||||
- Extracting the token expiration time (`jwt["exp"]`)
|
- Extracting the token expiration time (`jwt["exp"]`)
|
||||||
@@ -272,14 +281,28 @@ Here are some examples of how these methods can be utilized:
|
|||||||
```dart
|
```dart
|
||||||
String jwt = "your.jwt.token";
|
String jwt = "your.jwt.token";
|
||||||
// Returns a `DateTime?` when the token expires
|
// Returns a `DateTime?` when the token expires
|
||||||
final DateTime? email = jwt.jwtExpiryTime();
|
final DateTime? email = jwt.jwt.expiryTime;
|
||||||
```
|
```
|
||||||
|
|
||||||
- Extracting the user ID (`jwt["uid"]`)
|
- Extracting the user ID (`jwt["uid"]`)
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
String jwt = "your.jwt.token";
|
String jwt = "your.jwt.token";
|
||||||
final String? uid = jwt.jwtUserId(); // Returns the UID value from the token
|
final String? uid = jwt.jwt.userId; // Returns the UID value from the token
|
||||||
|
```
|
||||||
|
|
||||||
|
- Extracting the given name (`jwt["given_name"]`)
|
||||||
|
|
||||||
|
```dart
|
||||||
|
String jwt = "your.jwt.token";
|
||||||
|
final String? uid = jwt.jwt.givenName; // Returns the given name from the token
|
||||||
|
```
|
||||||
|
|
||||||
|
- Extracting the family name (`jwt["family_name"]`)
|
||||||
|
|
||||||
|
```dart
|
||||||
|
String jwt = "your.jwt.token";
|
||||||
|
final String? uid = jwt.jwt.familyName; // Returns the family name from the token
|
||||||
```
|
```
|
||||||
|
|
||||||
### String Utilities
|
### String Utilities
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ library arcane_helper_utils;
|
|||||||
|
|
||||||
export "package:arcane_helper_utils/src/extensions/date_time.dart";
|
export "package:arcane_helper_utils/src/extensions/date_time.dart";
|
||||||
export "package:arcane_helper_utils/src/extensions/dynamic.dart";
|
export "package:arcane_helper_utils/src/extensions/dynamic.dart";
|
||||||
|
export "package:arcane_helper_utils/src/extensions/jwt.dart";
|
||||||
export "package:arcane_helper_utils/src/extensions/list.dart";
|
export "package:arcane_helper_utils/src/extensions/list.dart";
|
||||||
export "package:arcane_helper_utils/src/extensions/string.dart";
|
export "package:arcane_helper_utils/src/extensions/string.dart";
|
||||||
export "package:arcane_helper_utils/src/extensions/string_jwt.dart";
|
|
||||||
export "package:arcane_helper_utils/src/utils/json_converter.dart";
|
export "package:arcane_helper_utils/src/utils/json_converter.dart";
|
||||||
export "package:arcane_helper_utils/src/utils/ticker.dart";
|
export "package:arcane_helper_utils/src/utils/ticker.dart";
|
||||||
|
|||||||
@@ -1,79 +1,12 @@
|
|||||||
import "dart:convert";
|
import "dart:convert";
|
||||||
|
|
||||||
|
typedef JwtPayload = Map<String, dynamic>;
|
||||||
|
|
||||||
/// An extension on `String` to extract useful information from JSON Web Tokens (JWT).
|
/// 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
|
/// This extension provides methods to decode a JWT string and retrieve common
|
||||||
/// fields like email, expiration time, and user ID.
|
/// fields like email, expiration time, and user ID.
|
||||||
extension JWTUtility on String {
|
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.
|
/// Decodes a base64 URL-encoded string.
|
||||||
///
|
///
|
||||||
/// This method replaces the URL-safe characters in the base64 string (`-` and `_`)
|
/// This method replaces the URL-safe characters in the base64 string (`-` and `_`)
|
||||||
@@ -111,20 +44,132 @@ extension JWTUtility on String {
|
|||||||
///
|
///
|
||||||
/// Example:
|
/// Example:
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// Map<String, dynamic> payload = _parseJwt("your.jwt.token");
|
/// Map<String, dynamic> payload = parseJwt("your.jwt.token");
|
||||||
/// ```
|
/// ```
|
||||||
Map<String, dynamic> _parseJwt(String token) {
|
JwtPayload get jwt {
|
||||||
final parts = token.split(".");
|
final parts = this.split(".");
|
||||||
if (parts.length != 3) {
|
if (parts.length != 3) {
|
||||||
throw Exception("invalid token");
|
throw InvalidTokenException();
|
||||||
}
|
}
|
||||||
|
|
||||||
final payload = _decodeBase64(parts[1]);
|
final payload = _decodeBase64(parts[1]);
|
||||||
final dynamic payloadMap = json.decode(payload);
|
final payloadMap = json.decode(payload) as JwtPayload?;
|
||||||
if (payloadMap is! Map<String, dynamic>) {
|
if (payloadMap is! JwtPayload) {
|
||||||
throw Exception("invalid payload");
|
throw InvalidPayloadException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return payloadMap;
|
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 {}
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
name: arcane_helper_utils
|
name: arcane_helper_utils
|
||||||
description: Provides a variety of helpful utilities and extensions for Flutter
|
description: Provides a variety of helpful utilities and extensions for Flutter
|
||||||
and Dart.
|
and Dart.
|
||||||
version: 1.3.2
|
version: 1.4.0
|
||||||
repository: https://github.com/hanskokx/arcane_helper_utils
|
repository: https://github.com/hanskokx/arcane_helper_utils
|
||||||
issue_tracker: https://github.com/hanskokx/arcane_helper_utils/issues
|
issue_tracker: https://github.com/hanskokx/arcane_helper_utils/issues
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import "package:arcane_helper_utils/arcane_helper_utils.dart";
|
||||||
|
import "package:test/test.dart";
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// Example JWT token for testing
|
||||||
|
const String validToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
|
||||||
|
"eyJzdWIiOiJ0ZXN0QGV4YW1wbGUuY29tIiwiZXhwIjoxNzM1Njg5NjAwLCJ1aWQiOiIxMjM0NTYiLCJnaXZlbl9uYW1lIjoiZ2l2ZW4iLCJmYW1pbHlfbmFtZSI6ImZhbWlseSJ9."
|
||||||
|
"Ki_D9fOhv7bLe86j6fdZ1guNGI7ldKSeeANUfinwNtc";
|
||||||
|
|
||||||
|
group("JWTUtility", () {
|
||||||
|
test("jwt getter parses a valid JWT", () {
|
||||||
|
expect(validToken.jwt, isNotNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jwt getter throws an exception for invalid token", () {
|
||||||
|
expect(() => "invalid.token".jwt, throwsException);
|
||||||
|
expect(() => "".jwt, throwsException);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jwt.email extracts email correctly", () {
|
||||||
|
expect(validToken.jwt.email, "test@example.com");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jwt.email throws an exception for invalid token", () {
|
||||||
|
expect(
|
||||||
|
() => "invalid.token".jwt.email,
|
||||||
|
throwsA(isA<InvalidTokenException>()),
|
||||||
|
);
|
||||||
|
expect(() => "".jwt.email, throwsA(isA<InvalidTokenException>()));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jwt.givenName extracts given name correctly", () {
|
||||||
|
expect(validToken.jwt.givenName, "given");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jwt.givenName throws an exception for invalid token", () {
|
||||||
|
expect(
|
||||||
|
() => "invalid.token".jwt.givenName,
|
||||||
|
throwsA(isA<InvalidTokenException>()),
|
||||||
|
);
|
||||||
|
expect(() => "".jwt.givenName, throwsA(isA<InvalidTokenException>()));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jwt.familyName extracts family name correctly", () {
|
||||||
|
expect(validToken.jwt.familyName, "family");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jwt.familyName returns null for invalid token", () {
|
||||||
|
expect(
|
||||||
|
() => "invalid.token".jwt.familyName,
|
||||||
|
throwsA(isA<InvalidTokenException>()),
|
||||||
|
);
|
||||||
|
expect(() => "".jwt.familyName, throwsA(isA<InvalidTokenException>()));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jwt.expiryTime extracts expiry time correctly", () {
|
||||||
|
final DateTime? expiry = validToken.jwt.expiryTime;
|
||||||
|
expect(expiry, isNotNull);
|
||||||
|
expect(expiry?.year, 2025); // Based on the exp value in the test token
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jwt.expiryTime throws an exception for invalid token", () {
|
||||||
|
expect(
|
||||||
|
() => "invalid.token".jwt.expiryTime,
|
||||||
|
throwsA(isA<InvalidTokenException>()),
|
||||||
|
);
|
||||||
|
expect(() => "".jwt.expiryTime, throwsA(isA<InvalidTokenException>()));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jwt.userId extracts user ID correctly", () {
|
||||||
|
expect(validToken.jwt.userId, "123456");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jwt.userId throws an exception for invalid token", () {
|
||||||
|
expect(
|
||||||
|
() => "invalid.token".jwt.userId,
|
||||||
|
throwsA(isA<InvalidTokenException>()),
|
||||||
|
);
|
||||||
|
expect(() => "".jwt.userId, throwsA(isA<InvalidTokenException>()));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
import "package:arcane_helper_utils/arcane_helper_utils.dart";
|
|
||||||
import "package:test/test.dart";
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
// Example JWT token for testing
|
|
||||||
const String validToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
|
|
||||||
"eyJzdWIiOiJ0ZXN0QGV4YW1wbGUuY29tIiwiZXhwIjoxNzM1Njg5NjAwLCJ1aWQiOiIxMjM0NTYifQ."
|
|
||||||
"signature";
|
|
||||||
|
|
||||||
group("JWTUtility", () {
|
|
||||||
test("jwtEmail extracts email correctly", () {
|
|
||||||
expect(validToken.jwtEmail(), "test@example.com");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("jwtEmail returns null for invalid token", () {
|
|
||||||
expect("invalid.token".jwtEmail(), null);
|
|
||||||
expect("".jwtEmail(), null);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("jwtExpiryTime extracts expiry time correctly", () {
|
|
||||||
final DateTime? expiry = validToken.jwtExpiryTime();
|
|
||||||
expect(expiry, isNotNull);
|
|
||||||
expect(expiry?.year, 2025); // Based on the exp value in the test token
|
|
||||||
});
|
|
||||||
|
|
||||||
test("jwtExpiryTime returns null for invalid token", () {
|
|
||||||
expect("invalid.token".jwtExpiryTime(), null);
|
|
||||||
expect("".jwtExpiryTime(), null);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("jwtUserId extracts user ID correctly", () {
|
|
||||||
expect(validToken.jwtUserId(), "123456");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("jwtUserId returns null for invalid token", () {
|
|
||||||
expect("invalid.token".jwtUserId(), null);
|
|
||||||
expect("".jwtUserId(), null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user