I Tried Out the Integration of Snowflake Cortex Agents with Microsoft Teams and Microsoft 365 Copilot

I Tried Out the Integration of Snowflake Cortex Agents with Microsoft Teams and Microsoft 365 Copilot

A summary of how to set up Snowflake Cortex Agents for use from Microsoft Teams and Microsoft 365 Copilot, including tests of user mapping and network policy behavior.
2026.11.01

This page has been translated by machine translation. View original

Introduction

Snowflake provides an integration that lets you use Cortex Agents from Microsoft Teams and Microsoft 365 Copilot.
This article covers the setup required to query an agent from Teams, along with what I observed when checking user mapping and network policy behavior.

Overview of the Cortex Agents Microsoft Teams Integration

This feature is described in the following documentation.

https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents-teams-integration

This feature embeds Cortex Agents into Microsoft Teams and Microsoft 365 Copilot, allowing you to query Snowflake data in natural language from a chat. Responses are returned as text, tables, and charts. You can use it as a dedicated Bot app in Teams, and as an agent within Copilot in Microsoft 365 Copilot.

Authentication uses External OAuth via Microsoft Entra ID. Based on the token issued by Entra ID, the request is mapped to a Snowflake user, and the agent runs with that user's default role.

Regarding data processing, the Bot backend runs in Snowflake's Azure East US 2 region. Therefore, regardless of which region your Snowflake account is in, intermediate processing in Azure East US 2 takes place when using this integration. For accounts in regions other than Azure East US 2, you must consent to this when connecting the Teams app to your Snowflake account.

The overall flow is as follows.

Teams の Bot に問い合わせ
  → Entra ID にサインイン
  → Entra ID がトークン(JWT)を発行
  → Bot がトークンを付けて Cortex Agents API を呼び出し
  → Snowflake のセキュリティ統合がトークンを検証し、Snowflake ユーザーに紐づけ
  → ユーザーのデフォルトロールでエージェントを実行

The main prerequisites and limitations are as follows.

  • Entra ID users and Snowflake users must be mapped one-to-one
  • Agent execution depends on the user's default role. Administrative roles such as ACCOUNTADMIN cannot be used as the default role
  • It cannot be used with accounts configured with Private Link

Prerequisites

Verification Environment

I used the following environment.

  • Snowflake
    • Enterprise Edition (AWS Tokyo region)
    • Related objects such as the Cortex Agent and semantic view have already been created
    • Cross-region inference (CORTEX_ENABLED_CROSS_REGION) is set to AWS_APJ
  • Microsoft 365
    • Prepared a verification tenant with a Microsoft 365 Business Standard trial, and assigned a Teams Essentials license to the user
    • Worked as an Entra ID Global Administrator

Microsoft 365 Business Standard Trial

First, start a Microsoft 365 Business Standard trial from the following page.

https://www.microsoft.com/ja-jp/microsoft-365/business/microsoft-365-business-standard

Once the trial has started, note down the Entra ID tenant ID from "Overview" in the Microsoft Entra admin center. The tenant ID will be used later to create the Snowflake security integration and for the Entra ID admin consent.

Creating a Cortex Agent

On the Snowflake side, I use the agent created following the contents of the article below. The agent is used with the yasuhara_dev role.

https://dev.classmethod.jp/articles/snowflake-cowork-automations-pupr-try/

Assigning a Teams License

From the Microsoft 365 admin center, select "Add other products."

Here, I added Microsoft Teams Essentials.

After adding the license, select the target user, check "Microsoft Teams Essentials" in the "Licenses and apps" tab, and save the changes.

After saving, confirm that the license is active for the target user.

Next, open https://teams.microsoft.com with the verification user and sign in.

If everything is fine, the Teams screen is displayed as shown below.

Snowflake-Side Configuration

Creating the Security Integration

First, create an External OAuth security integration with ACCOUNTADMIN. It is based on the template in the official documentation, with some modifications.

USE ROLE ACCOUNTADMIN;

CREATE OR REPLACE SECURITY INTEGRATION entra_id_cortex_agents_integration
    TYPE = EXTERNAL_OAUTH
    ENABLED = TRUE
    EXTERNAL_OAUTH_TYPE = AZURE
    EXTERNAL_OAUTH_ISSUER = 'https://login.microsoftonline.com/<tenant-id>/v2.0'
    EXTERNAL_OAUTH_JWS_KEYS_URL = 'https://login.microsoftonline.com/<tenant-id>/discovery/v2.0/keys'
    EXTERNAL_OAUTH_AUDIENCE_LIST = ('5a840489-78db-4a42-8772-47be9d833efe')
    EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM = 'email'
    EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE = 'EMAIL_ADDRESS'
    EXTERNAL_OAUTH_ANY_ROLE_MODE = 'ENABLE'
    EXTERNAL_OAUTH_ALLOWED_ROLES_LIST = ('YASUHARA_DEV');

For <tenant-id>, specify the tenant ID you noted earlier. Other points are as follows.

  • EXTERNAL_OAUTH_AUDIENCE_LIST
    • This is the ID of the "Snowflake Cortex Agents Bot OAuth Resource" app provided by Snowflake, and is a fixed value
  • EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM
    • This time I limited the mapping to email addresses
  • EXTERNAL_OAUTH_ALLOWED_ROLES_LIST
    • Limits the roles that can be used via Teams

Note that I did not specify EXTERNAL_OAUTH_BLOCKED_ROLES_LIST. Even when it is not specified, ACCOUNTADMIN, ORGADMIN, GLOBALORGADMIN, and SECURITYADMIN are blocked by default.

Creating a Snowflake User

Next, create a Snowflake user corresponding to the user who will sign in to Teams. The key point is that EMAIL must match the Entra ID user name. Since the user logs in only via External OAuth, no password is set.

This user will also be used later to connect the Teams app to the Snowflake account (an administrator operation). For that reason, I set DEFAULT_SECONDARY_ROLES = ('ALL') so that ACCOUNTADMIN, which will be granted later, can be used as a secondary role.

USE ROLE USERADMIN;

CREATE OR REPLACE USER teams_test_user
    TYPE = PERSON
    EMAIL = '<user>@<tenant>.onmicrosoft.com'
    DEFAULT_ROLE = 'YASUHARA_DEV'
    DEFAULT_WAREHOUSE = 'COMPUTE_WH'
    DEFAULT_SECONDARY_ROLES = ('ALL');

USE ROLE SECURITYADMIN;
GRANT ROLE yasuhara_dev TO USER teams_test_user;

The default role YASUHARA_DEV has already been granted usage privileges on the agent, semantic view, warehouse, and so on, as well as the SNOWFLAKE.CORTEX_AGENT_USER database role.

Next, grant admin consent for the Snowflake apps on the Entra ID side. As a Global Administrator, open the following two URLs in a browser and consent to each. For <tenant-id>, specify the tenant ID.

https://login.microsoftonline.com/<tenant-id>/adminconsent?client_id=5a840489-78db-4a42-8772-47be9d833efe
https://login.microsoftonline.com/<tenant-id>/adminconsent?client_id=bfdfa2a2-bce5-4aee-ad3d-41ef70eb5086

The first is the OAuth Resource. It is an app representing the Snowflake API, and a confirmation screen is displayed once.

The second is the OAuth Client. It is an app representing the Teams app backend, and the confirmation screen is displayed twice.

After consenting, the following error is displayed in the browser, but as stated in the documentation, the consent has been completed. You can also confirm that the URL contains admin_consent=True.

{
  "error": {
    "code": "ServiceError",
    "message": "Missing required query string parameter: code. Url = https://unitedstates.token.botframework.com/.auth/web/redirect?admin_consent=True&tenant=<tenant-id>"
  }
}

After consenting, it is fine if the following two apps appear under "Enterprise applications" in the Entra admin center.

  • Snowflake Cortex Agents Bot OAuth Resource
  • Snowflake Cortex Agents Bot OAuth Client

Querying from Teams

Connecting the Teams App

Search for "Snowflake Cortex Agents" in "Apps" in Teams.

Select "Add" to add the app.

Once added, the chat screen with the Bot opens as shown below.

The first user in the organization to use the app needs to connect a Snowflake account to the app. This operation requires having the ACCOUNTADMIN or SECURITYADMIN role on the Snowflake side.

https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents-teams-integration#connect-your-snowflake-account-to-the-teams-app

Here, I granted ACCOUNTADMIN to the user created earlier. As mentioned above, the default role remains YASUHARA_DEV, and ACCOUNTADMIN is used as a secondary role.

USE ROLE ACCOUNTADMIN;
GRANT ROLE ACCOUNTADMIN TO USER teams_test_user;

When you talk to the Bot, you are asked to sign in, so sign in with your Entra ID account via "Sign in."

Because the Snowflake account connection needs to be configured the first time, select that you are the administrator (I'm the Snowflake administrator).

Specify the Snowflake account URL (<org>-<account>.snowflakecomputing.com) and connect.

Since this account is in the AWS Tokyo region, you are asked to consent to intermediate processing in Azure East US 2 (no data is stored). Review the content and consent.

Once connected, you can select the agent to use.

In this state, I asked, "Please create a daily summary report of the sales data."
As shown below, a response including tables and charts was returned.

Querying as a Non-Administrator User

Next, I add a user without administrator privileges to both Entra ID and Snowflake and try querying.

First, add the user in the Microsoft 365 admin center and assign a Teams license.

On the Snowflake side, I added the user with the following query. Here too, the Snowflake user's EMAIL must match the email address on the Entra ID side (in this case, the same as the user name, <user2>@<tenant>.onmicrosoft.com).

USE ROLE USERADMIN;
CREATE USER IF NOT EXISTS teams_min_user
    TYPE = PERSON
    EMAIL = '<user2>@<tenant>.onmicrosoft.com'
    DEFAULT_ROLE = 'YASUHARA_DEV'
    DEFAULT_WAREHOUSE = 'COMPUTE_WH'
    DEFAULT_SECONDARY_ROLES = ();

USE ROLE SECURITYADMIN;
GRANT ROLE yasuhara_dev TO USER teams_min_user;

For this user, the secondary roles are left empty so that it operates only with the privileges of the default role.

Sign in to Teams with the added user.

Add the Snowflake Cortex Agents app following the same steps as before, and sign in from the Bot.

The Snowflake account connected by the administrator could be used as is, the agents shown were those within the scope of the role's privileges, and no administrator settings were displayed.

I confirmed that a response was returned for the same query.

Network Policy Behavior

Network access control is described in the documentation below.

https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents-teams-integration#network-policies

The main characteristics, including what I found in this verification, are as follows.

  • Existing network policies apply. However, a network policy set on the security integration does not apply, so set it at the user level or account level
  • The ipaddr claim contained in the Entra ID token (the IP at the time of signing in to Microsoft) is used for evaluation
  • The IP used for evaluation is not updated until you sign out of the Bot and sign in again
  • If the connection to Microsoft is over IPv6, you need to add a network rule with TYPE = IPV6

Let's try this behavior. I set a user-level network policy on the non-administrator user from earlier. It allows my local IPv4 address and IPv6 range.

USE ROLE SECURITYADMIN;

CREATE NETWORK RULE IF NOT EXISTS <db>.<schema>.teams_test_allow_rule
    MODE = INGRESS
    TYPE = IPV4
    VALUE_LIST = ('<手元の IPv4 アドレス>/32');

CREATE OR REPLACE NETWORK RULE <db>.<schema>.teams_test_allow_rule_v6
    MODE = INGRESS
    TYPE = IPV6
    VALUE_LIST = ('<手元の IPv6 プレフィックス>::/64');

CREATE OR REPLACE NETWORK POLICY teams_test_policy
    ALLOWED_NETWORK_RULE_LIST = ('<db>.<schema>.teams_test_allow_rule', '<db>.<schema>.teams_test_allow_rule_v6');

ALTER USER teams_min_user SET NETWORK_POLICY = teams_test_policy;

With this in place, I connect from a network other than the allowed one. When blocked, an error like the one below is displayed in Teams.

The IP shown in the error matched the IPv6 address recorded in the Entra admin center sign-in logs ("Monitoring & health" → "Sign-in logs"). On the other hand, when logging in to Snowsight from the same PC and connection, it is recorded with IPv4.

This is because the connection in the verification environment supports both IPv4 and IPv6, and the address used differs depending on the destination. Microsoft's endpoints support IPv6, whereas Snowsight (app.snowflake.com) was connected to over IPv4. Which one is used depends on the user's network environment, so on an IPv4-only corporate network, for example, evaluation would likely be done with IPv4 even via Teams.

Also, logins via Teams are recorded in LOGIN_HISTORY, but CLIENT_IP was 0.0.0.0 in all cases. The IP used for evaluation could not be confirmed from the login history.

As described above, I confirmed that queries succeed from within the allowed range and are blocked from outside it.

On the other hand, after trying several patterns, I thought the following two points require attention.

Network policies are applied per network identifier type (IPv4 / IPv6)

The rules in an allowed list restrict only identifiers of the same type as the rule. With a policy containing only IPv4 rules, queries from Teams that were evaluated over IPv6 were not restricted and succeeded. Once an IPv6 rule is added, IPv6 connections are also evaluated against the allowed list, and anything outside the allowed range is blocked.

Therefore, if you operate with only IPv4 allow rules, IPv6 connections via Teams are not restricted. When restricting by IP, you need to check the IP used when users connect to Microsoft in the Entra sign-in logs, and then set rules for both IPv4 and IPv6.

https://docs.snowflake.com/en/user-guide/network-policies#interaction-between-allowed-lists-and-blocked-lists

The Bot retains the IP from the time of the first sign-in

I switched from the connection used for the first sign-in to a different connection, logged out of Teams, signed in again, and then tried querying. Even in this case, the IP of the first connection was used for evaluation.

Specifically, with only the first connection's range allowed, queries succeeded even from the other connection. Conversely, with only the other connection's range allowed, queries were blocked, and the error showed the IP of the first connection. The IP of the other connection was also recorded in the Entra sign-in logs, but the token used by the Bot appears not to have been updated.

As stated in the documentation, evaluation is based not on "where it is being used from now" but on "the IP at the time of signing in to Microsoft." If a user signs in within the corporate network and then takes the device outside, access may continue to be allowed until the token is refreshed. If you want strict location-based control, I think it is also worth considering combining it with Entra ID Conditional Access.

https://learn.microsoft.com/ja-jp/entra/identity/conditional-access/overview

Querying from Microsoft 365 Copilot

Finally, I try querying from Microsoft 365 Copilot with the same settings. No additional configuration was needed on the Snowflake or Entra ID side.

After signing in from Copilot, I could select an agent just as in Teams, and querying was possible.

Conclusion

I tried out the Microsoft Teams integration of Cortex Agents and the behavior of network policies. The setup itself is simple, and I found it convenient that you can use Snowflake agents from a chat tool you use every day. Authentication is also OAuth-based via Entra ID, so users can simply sign in with their usual Microsoft account, and no Snowflake-side password is needed.
I hope this is helpful to someone.


Snowflakeの導入支援はクラスメソッドに!

クラスメソッドでは Snowflake の導入を支援しております。
製品の詳細や支援の内容についてお気軽にお問い合わせください。

Snowflakeの詳細を見る

Share this article