getDataFromToken method
Verify and extract the data within the id token
Implementation
Future<Map<String, dynamic>> getDataFromToken(String token) async {
final publicKeys = await _service.getPublicKeys();
final jws = JsonWebSignature.fromCompactSerialization(token);
/// Verify the ID token's header conforms to the following constraints
// Algorithm = "RS256"
if (jws.commonProtectedHeader['alg'] != 'RS256') {
throw Exception('Algorithm incorrect');
}
// Key ID Must correspond to one of the public keys listed at https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com
final keyId = jws.commonProtectedHeader['kid'] as String;
final key = publicKeys.keys[keyId];
if (key == null) {
throw Exception('Key ID is not found');
}
// Verify the ID token's payload conforms to the following constraints:
final data = jws.unverifiedPayload.jsonContent as Map<String, dynamic>;
final now = DateTime.now().toUtc().millisecondsSinceEpoch / 1000;
// exp Expiration time Must be in the future. The time is measured in seconds since the UNIX epoch.
final exp = data['exp'] as int?;
if (exp == null || exp < now) {
throw Exception('Token is expired');
}
// iat Issued-at time Must be in the past. The time is measured in seconds since the UNIX epoch.
final iat = data['iat'] as int?;
if (iat == null || iat > now + timeDiscrepancyInSeconds) {
throw Exception('Token is not issued in the past');
}
// aud Audience Must be your Firebase project ID, the unique identifier for your Firebase project, which can be found in the URL of that project's console.
final aud = data['aud'] as String?;
if (aud != projectId) {
throw Exception('Token project id does not correspond');
}
// iss Issuer Must be "https://securetoken.google.com/<projectId>", where <projectId> is the same project ID used for aud above.
final iss = data['iss'] as String?;
if (iss != 'https://securetoken.google.com/$projectId') {
throw Exception('Token issuer is not valid');
}
// sub Subject Must be a non-empty string and must be the uid of the user or device.
final sub = data['sub'] as String?;
if (sub == null || sub.isEmpty) {
throw Exception('Token subject is not found');
}
// auth_time Authentication time Must be in the past. The time when the user authenticated.
final authTime = data['auth_time'] as int?;
if (authTime == null || authTime > now + timeDiscrepancyInSeconds) {
throw Exception('Token is not authorized in the past');
}
// Finally, ensure that the ID token was signed by the private key corresponding to the token's kid claim.
final jwk = JsonWebKey.fromPem(key, keyId: keyId);
final keyStore = JsonWebKeyStore()..addKey(jwk);
// verify the signature
final verified = await jws.verify(keyStore);
if (verified != true) {
throw Exception('Token signature verification failed');
}
return data;
}