internal async Task VerifyTokenAsync()

in FirebaseAdmin/FirebaseAdmin/Auth/Jwt/FirebaseTokenVerifier.cs [162:264]


        internal async Task<FirebaseToken> VerifyTokenAsync(
            string token, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (string.IsNullOrEmpty(token))
            {
                throw new ArgumentException($"{this.shortName} must not be null or empty.");
            }

            string[] segments = token.Split('.');
            if (segments.Length != 3)
            {
                throw this.CreateException($"Incorrect number of segments in {this.shortName}.");
            }

            var header = JwtUtils.Decode<JsonWebSignature.Header>(segments[0]);
            var payload = JwtUtils.Decode<FirebaseToken.Args>(segments[1]);
            var projectIdMessage = $"Make sure the {this.shortName} comes from the same Firebase "
                + "project as the credential used to initialize this SDK.";
            var verifyTokenMessage = $"See {this.url} for details on how to retrieve a value "
                + $"{this.shortName}.";
            var issuer = this.issuer + this.ProjectId;
            string error = null;
            var errorCode = this.invalidTokenCode;
            var currentTimeInSeconds = this.clock.UnixTimestamp();

            if (!this.IsEmulatorMode && string.IsNullOrEmpty(header.KeyId))
            {
                if (payload.Audience == FirebaseAudience)
                {
                    error = $"{this.operation} expects {this.articledShortName}, but was given a custom "
                        + "token.";
                }
                else if (header.Algorithm == "HS256")
                {
                    error = $"{this.operation} expects {this.articledShortName}, but was given a legacy "
                        + "custom token.";
                }
                else
                {
                    error = $"Firebase {this.shortName} has no 'kid' claim.";
                }
            }
            else if (!this.IsEmulatorMode && header.Algorithm != "RS256")
            {
                error = $"Firebase {this.shortName} has incorrect algorithm. Expected RS256 but got "
                    + $"{header.Algorithm}. {verifyTokenMessage}";
            }
            else if (this.ProjectId != payload.Audience)
            {
                error = $"Firebase {this.shortName} has incorrect audience (aud) claim. Expected "
                    + $"{this.ProjectId} but got {payload.Audience}. {projectIdMessage} "
                    + $"{verifyTokenMessage}";
            }
            else if (payload.Issuer != issuer)
            {
                error = $"Firebase {this.shortName} has incorrect issuer (iss) claim. Expected "
                    + $"{issuer} but got {payload.Issuer}.  {projectIdMessage} {verifyTokenMessage}";
            }
            else if (payload.IssuedAtTimeSeconds - ClockSkewSeconds > currentTimeInSeconds)
            {
                error = $"Firebase {this.shortName} issued at future timestamp "
                    + $"{payload.IssuedAtTimeSeconds}. Expected to be less than "
                    + $"{currentTimeInSeconds}.";
            }
            else if (payload.ExpirationTimeSeconds + ClockSkewSeconds < currentTimeInSeconds)
            {
                error = $"Firebase {this.shortName} expired at {payload.ExpirationTimeSeconds}. "
                    + $"Expected to be greater than {currentTimeInSeconds}.";
                errorCode = this.expiredIdTokenCode;
            }
            else if (string.IsNullOrEmpty(payload.Subject))
            {
                error = $"Firebase {this.shortName} has no or empty subject (sub) claim.";
            }
            else if (payload.Subject.Length > 128)
            {
                error = $"Firebase {this.shortName} has a subject claim longer than 128 characters.";
            }
            else if (this.TenantId != null && this.TenantId != payload.Firebase?.Tenant)
            {
                error = $"Firebase {this.shortName} has incorrect tenant ID. Expected "
                    + $"{this.TenantId} but got {payload.Firebase?.Tenant}";
                errorCode = AuthErrorCode.TenantIdMismatch;
            }

            if (error != null)
            {
                throw this.CreateException(error, errorCode);
            }

            await this.VerifySignatureAsync(segments, header.KeyId, cancellationToken)
                .ConfigureAwait(false);
            var allClaims = JwtUtils.Decode<Dictionary<string, object>>(segments[1]);

            // Remove standard claims, so that only custom claims would remain.
            foreach (var claim in StandardClaims)
            {
                allClaims.Remove(claim);
            }

            payload.Claims = allClaims.ToImmutableDictionary();
            return new FirebaseToken(payload);
        }