We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
valid_token_issuers incorrectly populated during SingleTenant validation
### [Github issues](https://github.com/Microsoft/botbuilder-python) should be used for bugs and feature requests. Use [Stack Overflow](https://stackoverflow.com/questions/tagged/botframework) for general "how-to" questions. 

## Version
4.15.0

## Describe the bug
Tenant specific token issuers (valid_token_issuers) are added as a nested element, instead of individual issuers.

## To Reproduce
Steps to reproduce the behavior:
Authenticating with app_type 'SingleTenant' will result in unauthorized requests.

## Expected behavior
Tenant specific token issues are treated as valid.



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `libraries/botframework-connector/botframework/connector/auth/skill_validation.py`
Content:
```
1 # Copyright (c) Microsoft Corporation. All rights reserved.
2 # Licensed under the MIT License.
3 
4 from datetime import timedelta
5 from typing import Dict, Union
6 
7 import jwt
8 
9 from .authentication_configuration import AuthenticationConfiguration
10 from .authentication_constants import AuthenticationConstants
11 from .claims_identity import ClaimsIdentity
12 from .credential_provider import CredentialProvider
13 from .government_constants import GovernmentConstants
14 from .verify_options import VerifyOptions
15 from .jwt_token_extractor import JwtTokenExtractor
16 from .channel_provider import ChannelProvider
17 
18 
19 class SkillValidation:
20     # TODO: Remove circular dependcies after C# refactor
21     # pylint: disable=import-outside-toplevel
22 
23     """
24     Validates JWT tokens sent to and from a Skill.
25     """
26 
27     @staticmethod
28     def is_skill_token(auth_header: str) -> bool:
29         """
30         Determines if a given Auth header is from from a skill to bot or bot to skill request.
31         :param auth_header: Bearer Token, in the "Bearer [Long String]" Format.
32         :return bool:
33         """
34         from .jwt_token_validation import JwtTokenValidation
35 
36         if not JwtTokenValidation.is_valid_token_format(auth_header):
37             return False
38 
39         bearer_token = auth_header.split(" ")[1]
40 
41         # Parse the Big Long String into an actual token.
42         token = jwt.decode(bearer_token, options={"verify_signature": False})
43         return SkillValidation.is_skill_claim(token)
44 
45     @staticmethod
46     def is_skill_claim(claims: Dict[str, object]) -> bool:
47         """
48         Checks if the given list of claims represents a skill.
49         :param claims: A dict of claims.
50         :return bool:
51         """
52         if (
53             claims.get(AuthenticationConstants.APP_ID_CLAIM, None)
54             == AuthenticationConstants.ANONYMOUS_SKILL_APP_ID
55         ):
56             return True
57 
58         if AuthenticationConstants.VERSION_CLAIM not in claims:
59             return False
60 
61         audience = claims.get(AuthenticationConstants.AUDIENCE_CLAIM)
62 
63         # The audience is https://api.botframework.com and not an appId.
64         if (
65             not audience
66             or audience == AuthenticationConstants.TO_BOT_FROM_CHANNEL_TOKEN_ISSUER
67         ):
68             return False
69 
70         from .jwt_token_validation import JwtTokenValidation
71 
72         app_id = JwtTokenValidation.get_app_id_from_claims(claims)
73 
74         if not app_id:
75             return False
76 
77         # Skill claims must contain and app ID and the AppID must be different than the audience.
78         return app_id != audience
79 
80     @staticmethod
81     async def authenticate_channel_token(
82         auth_header: str,
83         credentials: CredentialProvider,
84         channel_service_or_provider: Union[str, ChannelProvider],
85         channel_id: str,
86         auth_configuration: AuthenticationConfiguration,
87     ) -> ClaimsIdentity:
88         if auth_configuration is None:
89             raise Exception(
90                 "auth_configuration cannot be None in SkillValidation.authenticate_channel_token"
91             )
92 
93         from .jwt_token_validation import JwtTokenValidation
94 
95         if isinstance(channel_service_or_provider, ChannelProvider):
96             is_gov = channel_service_or_provider.is_government()
97         else:
98             is_gov = JwtTokenValidation.is_government(channel_service_or_provider)
99 
100         open_id_metadata_url = (
101             GovernmentConstants.TO_BOT_FROM_EMULATOR_OPENID_METADATA_URL
102             if is_gov
103             else AuthenticationConstants.TO_BOT_FROM_EMULATOR_OPENID_METADATA_URL
104         )
105 
106         token_validation_parameters = VerifyOptions(
107             issuer=[
108                 "https://sts.windows.net/d6d49420-f39b-4df7-a1dc-d59a935871db/",  # v3.1, 1.0 token
109                 "https://login.microsoftonline.com/d6d49420-f39b-4df7-a1dc-d59a935871db/v2.0",  # v3.1, 2.0 token
110                 "https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/",  # v3.2, 1.0 token
111                 "https://login.microsoftonline.com/f8cdef31-a31e-4b4a-93e4-5f571e91255a/v2.0",  # v3.2, 2.0 token
112                 "https://sts.windows.net/cab8a31a-1906-4287-a0d8-4eef66b95f6e/",  # US Gov, 1.0 token
113                 "https://login.microsoftonline.us/cab8a31a-1906-4287-a0d8-4eef66b95f6e/v2.0",  # US Gov, 2.0 token
114                 "https://login.microsoftonline.us/f8cdef31-a31e-4b4a-93e4-5f571e91255a/",  # US Gov, 1.0 token
115                 "https://login.microsoftonline.us/f8cdef31-a31e-4b4a-93e4-5f571e91255a/v2.0",  # US Gov, 2.0 token
116             ],
117             audience=None,
118             clock_tolerance=timedelta(minutes=5),
119             ignore_expiration=False,
120         )
121 
122         if auth_configuration.valid_token_issuers:
123             token_validation_parameters.issuer.append(
124                 auth_configuration.valid_token_issuers
125             )
126 
127         token_extractor = JwtTokenExtractor(
128             token_validation_parameters,
129             open_id_metadata_url,
130             AuthenticationConstants.ALLOWED_SIGNING_ALGORITHMS,
131         )
132 
133         identity = await token_extractor.get_identity_from_auth_header(
134             auth_header, channel_id, auth_configuration.required_endorsements
135         )
136         await SkillValidation._validate_identity(identity, credentials)
137 
138         return identity
139 
140     @staticmethod
141     def create_anonymous_skill_claim():
142         """
143         Creates a ClaimsIdentity for an anonymous (unauthenticated) skill.
144         :return ClaimsIdentity:
145         """
146         return ClaimsIdentity(
147             {
148                 AuthenticationConstants.APP_ID_CLAIM: AuthenticationConstants.ANONYMOUS_SKILL_APP_ID
149             },
150             True,
151             AuthenticationConstants.ANONYMOUS_AUTH_TYPE,
152         )
153 
154     @staticmethod
155     async def _validate_identity(
156         identity: ClaimsIdentity, credentials: CredentialProvider
157     ):
158         if not identity:
159             # No valid identity. Not Authorized.
160             raise PermissionError("Invalid Identity")
161 
162         if not identity.is_authenticated:
163             # The token is in some way invalid. Not Authorized.
164             raise PermissionError("Token Not Authenticated")
165 
166         version_claim = identity.claims.get(AuthenticationConstants.VERSION_CLAIM)
167         if not version_claim:
168             # No version claim
169             raise PermissionError(
170                 f"'{AuthenticationConstants.VERSION_CLAIM}' claim is required on skill Tokens."
171             )
172 
173         # Look for the "aud" claim, but only if issued from the Bot Framework
174         audience_claim = identity.claims.get(AuthenticationConstants.AUDIENCE_CLAIM)
175         if not audience_claim:
176             # Claim is not present or doesn't have a value. Not Authorized.
177             raise PermissionError(
178                 f"'{AuthenticationConstants.AUDIENCE_CLAIM}' claim is required on skill Tokens."
179             )
180 
181         if not await credentials.is_valid_appid(audience_claim):
182             # The AppId is not valid. Not Authorized.
183             raise PermissionError("Invalid audience.")
184 
185         from .jwt_token_validation import JwtTokenValidation
186 
187         app_id = JwtTokenValidation.get_app_id_from_claims(identity.claims)
188         if not app_id:
189             # Invalid AppId
190             raise PermissionError("Invalid app_id.")
191
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/libraries/botframework-connector/botframework/connector/auth/skill_validation.py b/libraries/botframework-connector/botframework/connector/auth/skill_validation.py
--- a/libraries/botframework-connector/botframework/connector/auth/skill_validation.py
+++ b/libraries/botframework-connector/botframework/connector/auth/skill_validation.py
@@ -120,7 +120,7 @@
         )
 
         if auth_configuration.valid_token_issuers:
-            token_validation_parameters.issuer.append(
+            token_validation_parameters.issuer.extend(
                 auth_configuration.valid_token_issuers
             )

{"golden_diff": "diff --git a/libraries/botframework-connector/botframework/connector/auth/skill_validation.py b/libraries/botframework-connector/botframework/connector/auth/skill_validation.py\n--- a/libraries/botframework-connector/botframework/connector/auth/skill_validation.py\n+++ b/libraries/botframework-connector/botframework/connector/auth/skill_validation.py\n@@ -120,7 +120,7 @@\n         )\n \n         if auth_configuration.valid_token_issuers:\n-            token_validation_parameters.issuer.append(\n+            token_validation_parameters.issuer.extend(\n                 auth_configuration.valid_token_issuers\n             )\n", "issue": "valid_token_issuers incorrectly populated during SingleTenant validation\n### [Github issues](https://github.com/Microsoft/botbuilder-python) should be used for bugs and feature requests. Use [Stack Overflow](https://stackoverflow.com/questions/tagged/botframework) for general \"how-to\" questions. \r\n\r\n## Version\r\n4.15.0\r\n\r\n## Describe the bug\r\nTenant specific token issuers (valid_token_issuers) are added as a nested element, instead of individual issuers.\r\n\r\n## To Reproduce\r\nSteps to reproduce the behavior:\r\nAuthenticating with app_type 'SingleTenant' will result in unauthorized requests.\r\n\r\n## Expected behavior\r\nTenant specific token issues are treated as valid.\r\n\r\n\n", "before_files": [{"content": "# Copyright (c) Microsoft Corporation. All rights reserved.\n# Licensed under the MIT License.\n\nfrom datetime import timedelta\nfrom typing import Dict, Union\n\nimport jwt\n\nfrom .authentication_configuration import AuthenticationConfiguration\nfrom .authentication_constants import AuthenticationConstants\nfrom .claims_identity import ClaimsIdentity\nfrom .credential_provider import CredentialProvider\nfrom .government_constants import GovernmentConstants\nfrom .verify_options import VerifyOptions\nfrom .jwt_token_extractor import JwtTokenExtractor\nfrom .channel_provider import ChannelProvider\n\n\nclass SkillValidation:\n    # TODO: Remove circular dependcies after C# refactor\n    # pylint: disable=import-outside-toplevel\n\n    \"\"\"\n    Validates JWT tokens sent to and from a Skill.\n    \"\"\"\n\n    @staticmethod\n    def is_skill_token(auth_header: str) -> bool:\n        \"\"\"\n        Determines if a given Auth header is from from a skill to bot or bot to skill request.\n        :param auth_header: Bearer Token, in the \"Bearer [Long String]\" Format.\n        :return bool:\n        \"\"\"\n        from .jwt_token_validation import JwtTokenValidation\n\n        if not JwtTokenValidation.is_valid_token_format(auth_header):\n            return False\n\n        bearer_token = auth_header.split(\" \")[1]\n\n        # Parse the Big Long String into an actual token.\n        token = jwt.decode(bearer_token, options={\"verify_signature\": False})\n        return SkillValidation.is_skill_claim(token)\n\n    @staticmethod\n    def is_skill_claim(claims: Dict[str, object]) -> bool:\n        \"\"\"\n        Checks if the given list of claims represents a skill.\n        :param claims: A dict of claims.\n        :return bool:\n        \"\"\"\n        if (\n            claims.get(AuthenticationConstants.APP_ID_CLAIM, None)\n            == AuthenticationConstants.ANONYMOUS_SKILL_APP_ID\n        ):\n            return True\n\n        if AuthenticationConstants.VERSION_CLAIM not in claims:\n            return False\n\n        audience = claims.get(AuthenticationConstants.AUDIENCE_CLAIM)\n\n        # The audience is https://api.botframework.com and not an appId.\n        if (\n            not audience\n            or audience == AuthenticationConstants.TO_BOT_FROM_CHANNEL_TOKEN_ISSUER\n        ):\n            return False\n\n        from .jwt_token_validation import JwtTokenValidation\n\n        app_id = JwtTokenValidation.get_app_id_from_claims(claims)\n\n        if not app_id:\n            return False\n\n        # Skill claims must contain and app ID and the AppID must be different than the audience.\n        return app_id != audience\n\n    @staticmethod\n    async def authenticate_channel_token(\n        auth_header: str,\n        credentials: CredentialProvider,\n        channel_service_or_provider: Union[str, ChannelProvider],\n        channel_id: str,\n        auth_configuration: AuthenticationConfiguration,\n    ) -> ClaimsIdentity:\n        if auth_configuration is None:\n            raise Exception(\n                \"auth_configuration cannot be None in SkillValidation.authenticate_channel_token\"\n            )\n\n        from .jwt_token_validation import JwtTokenValidation\n\n        if isinstance(channel_service_or_provider, ChannelProvider):\n            is_gov = channel_service_or_provider.is_government()\n        else:\n            is_gov = JwtTokenValidation.is_government(channel_service_or_provider)\n\n        open_id_metadata_url = (\n            GovernmentConstants.TO_BOT_FROM_EMULATOR_OPENID_METADATA_URL\n            if is_gov\n            else AuthenticationConstants.TO_BOT_FROM_EMULATOR_OPENID_METADATA_URL\n        )\n\n        token_validation_parameters = VerifyOptions(\n            issuer=[\n                \"https://sts.windows.net/d6d49420-f39b-4df7-a1dc-d59a935871db/\",  # v3.1, 1.0 token\n                \"https://login.microsoftonline.com/d6d49420-f39b-4df7-a1dc-d59a935871db/v2.0\",  # v3.1, 2.0 token\n                \"https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/\",  # v3.2, 1.0 token\n                \"https://login.microsoftonline.com/f8cdef31-a31e-4b4a-93e4-5f571e91255a/v2.0\",  # v3.2, 2.0 token\n                \"https://sts.windows.net/cab8a31a-1906-4287-a0d8-4eef66b95f6e/\",  # US Gov, 1.0 token\n                \"https://login.microsoftonline.us/cab8a31a-1906-4287-a0d8-4eef66b95f6e/v2.0\",  # US Gov, 2.0 token\n                \"https://login.microsoftonline.us/f8cdef31-a31e-4b4a-93e4-5f571e91255a/\",  # US Gov, 1.0 token\n                \"https://login.microsoftonline.us/f8cdef31-a31e-4b4a-93e4-5f571e91255a/v2.0\",  # US Gov, 2.0 token\n            ],\n            audience=None,\n            clock_tolerance=timedelta(minutes=5),\n            ignore_expiration=False,\n        )\n\n        if auth_configuration.valid_token_issuers:\n            token_validation_parameters.issuer.append(\n                auth_configuration.valid_token_issuers\n            )\n\n        token_extractor = JwtTokenExtractor(\n            token_validation_parameters,\n            open_id_metadata_url,\n            AuthenticationConstants.ALLOWED_SIGNING_ALGORITHMS,\n        )\n\n        identity = await token_extractor.get_identity_from_auth_header(\n            auth_header, channel_id, auth_configuration.required_endorsements\n        )\n        await SkillValidation._validate_identity(identity, credentials)\n\n        return identity\n\n    @staticmethod\n    def create_anonymous_skill_claim():\n        \"\"\"\n        Creates a ClaimsIdentity for an anonymous (unauthenticated) skill.\n        :return ClaimsIdentity:\n        \"\"\"\n        return ClaimsIdentity(\n            {\n                AuthenticationConstants.APP_ID_CLAIM: AuthenticationConstants.ANONYMOUS_SKILL_APP_ID\n            },\n            True,\n            AuthenticationConstants.ANONYMOUS_AUTH_TYPE,\n        )\n\n    @staticmethod\n    async def _validate_identity(\n        identity: ClaimsIdentity, credentials: CredentialProvider\n    ):\n        if not identity:\n            # No valid identity. Not Authorized.\n            raise PermissionError(\"Invalid Identity\")\n\n        if not identity.is_authenticated:\n            # The token is in some way invalid. Not Authorized.\n            raise PermissionError(\"Token Not Authenticated\")\n\n        version_claim = identity.claims.get(AuthenticationConstants.VERSION_CLAIM)\n        if not version_claim:\n            # No version claim\n            raise PermissionError(\n                f\"'{AuthenticationConstants.VERSION_CLAIM}' claim is required on skill Tokens.\"\n            )\n\n        # Look for the \"aud\" claim, but only if issued from the Bot Framework\n        audience_claim = identity.claims.get(AuthenticationConstants.AUDIENCE_CLAIM)\n        if not audience_claim:\n            # Claim is not present or doesn't have a value. Not Authorized.\n            raise PermissionError(\n                f\"'{AuthenticationConstants.AUDIENCE_CLAIM}' claim is required on skill Tokens.\"\n            )\n\n        if not await credentials.is_valid_appid(audience_claim):\n            # The AppId is not valid. Not Authorized.\n            raise PermissionError(\"Invalid audience.\")\n\n        from .jwt_token_validation import JwtTokenValidation\n\n        app_id = JwtTokenValidation.get_app_id_from_claims(identity.claims)\n        if not app_id:\n            # Invalid AppId\n            raise PermissionError(\"Invalid app_id.\")\n", "path": "libraries/botframework-connector/botframework/connector/auth/skill_validation.py"}], "after_files": [{"content": "# Copyright (c) Microsoft Corporation. All rights reserved.\n# Licensed under the MIT License.\n\nfrom datetime import timedelta\nfrom typing import Dict, Union\n\nimport jwt\n\nfrom .authentication_configuration import AuthenticationConfiguration\nfrom .authentication_constants import AuthenticationConstants\nfrom .claims_identity import ClaimsIdentity\nfrom .credential_provider import CredentialProvider\nfrom .government_constants import GovernmentConstants\nfrom .verify_options import VerifyOptions\nfrom .jwt_token_extractor import JwtTokenExtractor\nfrom .channel_provider import ChannelProvider\n\n\nclass SkillValidation:\n    # TODO: Remove circular dependcies after C# refactor\n    # pylint: disable=import-outside-toplevel\n\n    \"\"\"\n    Validates JWT tokens sent to and from a Skill.\n    \"\"\"\n\n    @staticmethod\n    def is_skill_token(auth_header: str) -> bool:\n        \"\"\"\n        Determines if a given Auth header is from from a skill to bot or bot to skill request.\n        :param auth_header: Bearer Token, in the \"Bearer [Long String]\" Format.\n        :return bool:\n        \"\"\"\n        from .jwt_token_validation import JwtTokenValidation\n\n        if not JwtTokenValidation.is_valid_token_format(auth_header):\n            return False\n\n        bearer_token = auth_header.split(\" \")[1]\n\n        # Parse the Big Long String into an actual token.\n        token = jwt.decode(bearer_token, options={\"verify_signature\": False})\n        return SkillValidation.is_skill_claim(token)\n\n    @staticmethod\n    def is_skill_claim(claims: Dict[str, object]) -> bool:\n        \"\"\"\n        Checks if the given list of claims represents a skill.\n        :param claims: A dict of claims.\n        :return bool:\n        \"\"\"\n        if (\n            claims.get(AuthenticationConstants.APP_ID_CLAIM, None)\n            == AuthenticationConstants.ANONYMOUS_SKILL_APP_ID\n        ):\n            return True\n\n        if AuthenticationConstants.VERSION_CLAIM not in claims:\n            return False\n\n        audience = claims.get(AuthenticationConstants.AUDIENCE_CLAIM)\n\n        # The audience is https://api.botframework.com and not an appId.\n        if (\n            not audience\n            or audience == AuthenticationConstants.TO_BOT_FROM_CHANNEL_TOKEN_ISSUER\n        ):\n            return False\n\n        from .jwt_token_validation import JwtTokenValidation\n\n        app_id = JwtTokenValidation.get_app_id_from_claims(claims)\n\n        if not app_id:\n            return False\n\n        # Skill claims must contain and app ID and the AppID must be different than the audience.\n        return app_id != audience\n\n    @staticmethod\n    async def authenticate_channel_token(\n        auth_header: str,\n        credentials: CredentialProvider,\n        channel_service_or_provider: Union[str, ChannelProvider],\n        channel_id: str,\n        auth_configuration: AuthenticationConfiguration,\n    ) -> ClaimsIdentity:\n        if auth_configuration is None:\n            raise Exception(\n                \"auth_configuration cannot be None in SkillValidation.authenticate_channel_token\"\n            )\n\n        from .jwt_token_validation import JwtTokenValidation\n\n        if isinstance(channel_service_or_provider, ChannelProvider):\n            is_gov = channel_service_or_provider.is_government()\n        else:\n            is_gov = JwtTokenValidation.is_government(channel_service_or_provider)\n\n        open_id_metadata_url = (\n            GovernmentConstants.TO_BOT_FROM_EMULATOR_OPENID_METADATA_URL\n            if is_gov\n            else AuthenticationConstants.TO_BOT_FROM_EMULATOR_OPENID_METADATA_URL\n        )\n\n        token_validation_parameters = VerifyOptions(\n            issuer=[\n                \"https://sts.windows.net/d6d49420-f39b-4df7-a1dc-d59a935871db/\",  # v3.1, 1.0 token\n                \"https://login.microsoftonline.com/d6d49420-f39b-4df7-a1dc-d59a935871db/v2.0\",  # v3.1, 2.0 token\n                \"https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/\",  # v3.2, 1.0 token\n                \"https://login.microsoftonline.com/f8cdef31-a31e-4b4a-93e4-5f571e91255a/v2.0\",  # v3.2, 2.0 token\n                \"https://sts.windows.net/cab8a31a-1906-4287-a0d8-4eef66b95f6e/\",  # US Gov, 1.0 token\n                \"https://login.microsoftonline.us/cab8a31a-1906-4287-a0d8-4eef66b95f6e/v2.0\",  # US Gov, 2.0 token\n                \"https://login.microsoftonline.us/f8cdef31-a31e-4b4a-93e4-5f571e91255a/\",  # US Gov, 1.0 token\n                \"https://login.microsoftonline.us/f8cdef31-a31e-4b4a-93e4-5f571e91255a/v2.0\",  # US Gov, 2.0 token\n            ],\n            audience=None,\n            clock_tolerance=timedelta(minutes=5),\n            ignore_expiration=False,\n        )\n\n        if auth_configuration.valid_token_issuers:\n            token_validation_parameters.issuer.extend(\n                auth_configuration.valid_token_issuers\n            )\n\n        token_extractor = JwtTokenExtractor(\n            token_validation_parameters,\n            open_id_metadata_url,\n            AuthenticationConstants.ALLOWED_SIGNING_ALGORITHMS,\n        )\n\n        identity = await token_extractor.get_identity_from_auth_header(\n            auth_header, channel_id, auth_configuration.required_endorsements\n        )\n        await SkillValidation._validate_identity(identity, credentials)\n\n        return identity\n\n    @staticmethod\n    def create_anonymous_skill_claim():\n        \"\"\"\n        Creates a ClaimsIdentity for an anonymous (unauthenticated) skill.\n        :return ClaimsIdentity:\n        \"\"\"\n        return ClaimsIdentity(\n            {\n                AuthenticationConstants.APP_ID_CLAIM: AuthenticationConstants.ANONYMOUS_SKILL_APP_ID\n            },\n            True,\n            AuthenticationConstants.ANONYMOUS_AUTH_TYPE,\n        )\n\n    @staticmethod\n    async def _validate_identity(\n        identity: ClaimsIdentity, credentials: CredentialProvider\n    ):\n        if not identity:\n            # No valid identity. Not Authorized.\n            raise PermissionError(\"Invalid Identity\")\n\n        if not identity.is_authenticated:\n            # The token is in some way invalid. Not Authorized.\n            raise PermissionError(\"Token Not Authenticated\")\n\n        version_claim = identity.claims.get(AuthenticationConstants.VERSION_CLAIM)\n        if not version_claim:\n            # No version claim\n            raise PermissionError(\n                f\"'{AuthenticationConstants.VERSION_CLAIM}' claim is required on skill Tokens.\"\n            )\n\n        # Look for the \"aud\" claim, but only if issued from the Bot Framework\n        audience_claim = identity.claims.get(AuthenticationConstants.AUDIENCE_CLAIM)\n        if not audience_claim:\n            # Claim is not present or doesn't have a value. Not Authorized.\n            raise PermissionError(\n                f\"'{AuthenticationConstants.AUDIENCE_CLAIM}' claim is required on skill Tokens.\"\n            )\n\n        if not await credentials.is_valid_appid(audience_claim):\n            # The AppId is not valid. Not Authorized.\n            raise PermissionError(\"Invalid audience.\")\n\n        from .jwt_token_validation import JwtTokenValidation\n\n        app_id = JwtTokenValidation.get_app_id_from_claims(identity.claims)\n        if not app_id:\n            # Invalid AppId\n            raise PermissionError(\"Invalid app_id.\")\n", "path": "libraries/botframework-connector/botframework/connector/auth/skill_validation.py"}]}