Skip to content

Commit

Permalink
implement verify method
Browse files Browse the repository at this point in the history
  • Loading branch information
tkfinitefield committed May 23, 2024
1 parent 0df470b commit e1c1d3a
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 13 deletions.
14 changes: 8 additions & 6 deletions packages/dart_firebase_admin/lib/src/auth/token_verifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ class DecodedIdToken {

@internal
factory DecodedIdToken.fromMap(Map<String, Object?> map) {
final firebaseMap = Map<String, Object?>.from(map['firebase']! as Map);
return DecodedIdToken(
aud: map['aud']! as String,
authTime: DateTime.fromMillisecondsSinceEpoch(
Expand All @@ -314,18 +315,19 @@ class DecodedIdToken {
emailVerified: map['email_verified'] as bool?,
exp: map['exp']! as int,
firebase: TokenProvider(
identities: Map.from(map['firebase']! as Map),
signInProvider: map['sign_in_provider']! as String,
signInSecondFactor: map['sign_in_second_factor'] as String?,
secondFactorIdentifier: map['second_factor_identifier'] as String?,
tenant: map['tenant'] as String?,
identities: firebaseMap,
signInProvider: firebaseMap['sign_in_provider']! as String,
signInSecondFactor: firebaseMap['sign_in_second_factor'] as String?,
secondFactorIdentifier:
firebaseMap['second_factor_identifier'] as String?,
tenant: firebaseMap['tenant'] as String?,
),
iat: map['iat']! as int,
iss: map['iss']! as String,
phoneNumber: map['phone_number'] as String?,
picture: map['picture'] as String?,
sub: map['sub']! as String,
uid: map['uid']! as String,
uid: map['sub']! as String,
);
}

Expand Down
59 changes: 52 additions & 7 deletions packages/dart_firebase_admin/lib/src/utils/jwt.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@ import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
import 'package:http/http.dart' as http;
import 'package:meta/meta.dart';

const String jwtCallbackErrorPrefix =
'error in secret or public key callback: ';

const String moMatchingKidErrorMessage = 'no-matching-kid-error';
const String noKidInHeaderErrorMessage = 'no-kid-in-header-error';

/// Class for verifying unsigned (emulator) JWTs.
class EmulatorSignatureVerifier implements SignatureVerifier {
@override
Future<void> verify(String token) async {
// Signature checks skipped for emulator; no need to fetch public keys.
try {
return await verifyJwtSignature(
token,
SecretKey(''),
);
JWT.decode(token);
} on JWTInvalidException catch (e) {
if (e.message == 'invalid signature') return;
rethrow;
Expand Down Expand Up @@ -96,9 +99,51 @@ class PublicKeySignatureVerifier implements SignatureVerifier {
final KeyFetcher keyFetcher;

@override
Future<bool> verify(String token) {
throw UnimplementedError();
// verifyJwtSignature(token);
Future<void> verify(String token) async {
try {
final jwt = JWT.decode(token);
final kid = jwt.header?['kid'] as String?;

if (kid == null) {
throw JwtError(
JwtErrorCode.noKidInHeader,
noKidInHeaderErrorMessage,
);
}

final publicKeys = await keyFetcher.fetchPublicKeys();
final publicKey = publicKeys[kid];

if (publicKey == null) {
throw JwtError(
JwtErrorCode.noMatchingKid,
moMatchingKidErrorMessage,
);
}
JWT.verify(
token,
RSAPublicKey.cert(publicKey),
);
} on JWTExpiredException {
throw JwtError(
JwtErrorCode.tokenExpired,
'The provided token has expired. Get a fresh token from your client app and try again.',
);
} on JWTException catch (e) {
if (e.message.startsWith(jwtCallbackErrorPrefix)) {
final message = e.message.split(jwtCallbackErrorPrefix).last.trim();
JwtErrorCode code;
if (message == moMatchingKidErrorMessage) {
code = JwtErrorCode.noMatchingKid;
} else if (message == noKidInHeaderErrorMessage) {
code = JwtErrorCode.noKidInHeader;
} else {
code = JwtErrorCode.keyFetchError;
}
throw JwtError(code, message);
}
throw JwtError(JwtErrorCode.invalidSignature, e.message);
}
}
}

Expand Down

0 comments on commit e1c1d3a

Please sign in to comment.