microsoft/teams.net
Publicmirrored fromhttps://github.com/microsoft/teams.netAvailable
core/samples/OAuthFlowBot/Program.cs
211lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | // This sample demonstrates how to use OAuthFlow with two OAuth connections: |
| 5 | // - GraphConnection: Microsoft Graph (Azure AD v2) for user profile and calendar |
| 6 | // - GitHubConnection: GitHub for repositories |
| 7 | // |
| 8 | // Azure Bot resource must have two OAuth connection settings configured: |
| 9 | // | Connection name | Provider | Scopes | |
| 10 | // |-------------------|--------------|---------------------------| |
| 11 | // | GraphConnection | Azure AD v2 | User.Read Calendars.Read | |
| 12 | // | GitHubConnection | GitHub | repo read:user | |
| 13 | |
| 14 | using Microsoft.Teams.Apps; |
| 15 | using Microsoft.Teams.Apps.Handlers; |
| 16 | using Microsoft.Teams.Apps.OAuth; |
| 17 | using Microsoft.Teams.Apps.Schema; |
| 18 | |
| 19 | WebApplicationBuilder webAppBuilder = WebApplication.CreateSlimBuilder(args); |
| 20 | |
| 21 | // Configure OAuth flows at the DI level -- card text is set once here |
| 22 | webAppBuilder.Services.AddTeamsBotApplication(options => |
| 23 | { |
| 24 | options.AddOAuthFlow("sso", o => |
| 25 | { |
| 26 | o.OAuthCardText = "Sign in to your Microsoft account"; |
| 27 | o.SignInButtonText = "Sign In to Graph"; |
| 28 | }); |
| 29 | options.AddOAuthFlow("gh", o => |
| 30 | { |
| 31 | o.OAuthCardText = "Sign in to your GitHub account"; |
| 32 | o.SignInButtonText = "Sign In to GitHub"; |
| 33 | }); |
| 34 | }); |
| 35 | |
| 36 | WebApplication webApp = webAppBuilder.Build(); |
| 37 | |
| 38 | TeamsBotApplication bot = webApp.UseTeamsBotApplication(); |
| 39 | |
| 40 | // ==================== OAUTH FLOW SETUP ==================== |
| 41 | |
| 42 | // Get the pre-registered flows and attach callbacks |
| 43 | OAuthFlow graphAuth = bot.GetOAuthFlow("sso"); |
| 44 | OAuthFlow githubAuth = bot.GetOAuthFlow("gh"); |
| 45 | |
| 46 | graphAuth.OnSignInComplete(async (context, tokenResponse, ct) => |
| 47 | { |
| 48 | await context.SendActivityAsync($"User {context.Activity.From?.Name} connected to Microsoft Graph ({tokenResponse.ConnectionName})!", ct); |
| 49 | }); |
| 50 | |
| 51 | graphAuth.OnSignInFailure(async (context, failure, ct) => |
| 52 | { |
| 53 | await context.SendActivityAsync($"User {context.Activity.From?.Name} failed to connect to Microsoft Graph. {failure?.Message}", ct); |
| 54 | }); |
| 55 | |
| 56 | githubAuth.OnSignInComplete(async (context, tokenResponse, ct) => |
| 57 | { |
| 58 | await context.SendActivityAsync($"User {context.Activity.From?.Name} connected to GitHub ({tokenResponse.ConnectionName})!", ct); |
| 59 | }); |
| 60 | |
| 61 | githubAuth.OnSignInFailure(async (context, failure, ct) => |
| 62 | { |
| 63 | await context.SendActivityAsync($"User {context.Activity.From?.Name} failed to connect to GitHub. {failure?.Message}", ct); |
| 64 | }); |
| 65 | |
| 66 | // ==================== MESSAGE HANDLERS ==================== |
| 67 | |
| 68 | bot.OnMessage("(?i)^help$", async (context, ct) => |
| 69 | { |
| 70 | string helpText = """ |
| 71 | **OAuthFlow Bot** - Multi-connection OAuth sample |
| 72 | |
| 73 | Commands: |
| 74 | - `login` - Sign in to all connections |
| 75 | - `login graph` - Sign in to Microsoft Graph |
| 76 | - `login github` - Sign in to GitHub |
| 77 | - `status` - Show OAuth connection status |
| 78 | - `my ad user` - Get your Azure AD user (requires Graph) |
| 79 | - `my gh user` - Get your GitHub user (requires GitHub) |
| 80 | - `logout` - Sign out from all connections |
| 81 | - `logout graph` - Sign out from Graph only |
| 82 | - `logout github` - Sign out from GitHub only |
| 83 | - `help` - Show this message |
| 84 | """; |
| 85 | |
| 86 | await context.SendActivityAsync( |
| 87 | new MessageActivity(helpText) { TextFormat = TextFormats.Markdown }, ct); |
| 88 | }); |
| 89 | |
| 90 | bot.OnMessage("(?i)^login$", async (context, ct) => |
| 91 | { |
| 92 | string? tokenGitHub = await githubAuth.SignInAsync(context, ct); |
| 93 | string? tokenGraph = await graphAuth.SignInAsync(context, ct); |
| 94 | if (tokenGraph is not null) |
| 95 | { |
| 96 | await context.SendActivityAsync("Already signed in to Graph.", ct); |
| 97 | } |
| 98 | |
| 99 | if (tokenGitHub is not null) |
| 100 | { |
| 101 | await context.SendActivityAsync("Already signed in to GitHub.", ct); |
| 102 | } |
| 103 | |
| 104 | }); |
| 105 | |
| 106 | bot.OnMessage("(?i)^login graph$", async (context, ct) => |
| 107 | { |
| 108 | string? tokenGraph = await graphAuth.SignInAsync(context, ct); |
| 109 | if (tokenGraph is not null) |
| 110 | { |
| 111 | await context.SendActivityAsync("Already signed in to Graph.", ct); |
| 112 | } |
| 113 | // else: OAuthCard sent, SSO in progress |
| 114 | }); |
| 115 | |
| 116 | bot.OnMessage("(?i)^login github$", async (context, ct) => |
| 117 | { |
| 118 | string? tokenGitHub = await githubAuth.SignInAsync(context, ct); |
| 119 | if (tokenGitHub is not null) |
| 120 | { |
| 121 | await context.SendActivityAsync("Already signed in to GitHub.", ct); |
| 122 | } |
| 123 | }); |
| 124 | |
| 125 | bot.OnMessage("(?i)^status$", async (context, ct) => |
| 126 | { |
| 127 | // GetConnectionStatusAsync returns ALL connections -- no names needed |
| 128 | var statuses = await graphAuth.GetConnectionStatusAsync(context, ct); |
| 129 | var lines = statuses.Select(s => |
| 130 | $"- **{s.ConnectionName}** ({s.ServiceProviderDisplayName}): " + |
| 131 | $"{(s.HasToken == true ? "✅ connected" : "❌ not connected")}"); |
| 132 | |
| 133 | await context.SendActivityAsync( |
| 134 | new MessageActivity($"OAuth connections for {context.Activity.From?.Name} :\n" + string.Join("\n", lines)) |
| 135 | { |
| 136 | TextFormat = TextFormats.Markdown |
| 137 | }, ct); |
| 138 | }); |
| 139 | |
| 140 | bot.OnMessage("(?i)^my ad user", async (context, ct) => |
| 141 | { |
| 142 | string? token = await graphAuth.SignInAsync(context, ct); |
| 143 | if (token is null) return; |
| 144 | |
| 145 | using var http = new HttpClient(); |
| 146 | http.DefaultRequestHeaders.Authorization = new("Bearer", token); |
| 147 | |
| 148 | try |
| 149 | { |
| 150 | string response = await http.GetStringAsync( |
| 151 | "https://graph.microsoft.com/v1.0/me", ct); |
| 152 | await context.SendActivityAsync($"Your Azure AD user :\n```json\n{response}\n```", ct); |
| 153 | } |
| 154 | catch (HttpRequestException ex) |
| 155 | { |
| 156 | await context.SendActivityAsync($"Failed to fetch Azure AD user: {ex.Message}", ct); |
| 157 | } |
| 158 | }); |
| 159 | |
| 160 | bot.OnMessage("(?i)^my gh user$", async (context, ct) => |
| 161 | { |
| 162 | string? token = await githubAuth.SignInAsync(context, ct); |
| 163 | if (token is null) return; |
| 164 | |
| 165 | using var http = new HttpClient(); |
| 166 | http.DefaultRequestHeaders.Authorization = new("Bearer", token); |
| 167 | http.DefaultRequestHeaders.UserAgent.ParseAdd("TeamsBot/1.0"); |
| 168 | |
| 169 | try |
| 170 | { |
| 171 | string response = await http.GetStringAsync( |
| 172 | "https://api.github.com/user", ct); |
| 173 | await context.SendActivityAsync($"Your GitHub user :\n```json\n{response}\n```", ct); |
| 174 | } |
| 175 | catch (HttpRequestException ex) |
| 176 | { |
| 177 | await context.SendActivityAsync($"Failed to fetch GitHub user: {ex.Message}", ct); |
| 178 | } |
| 179 | }); |
| 180 | |
| 181 | bot.OnMessage("(?i)^logout$", async (context, ct) => |
| 182 | { |
| 183 | await graphAuth.SignOutAsync(context, ct); |
| 184 | await githubAuth.SignOutAsync(context, ct); |
| 185 | await context.SendActivityAsync("Signed out from all services.", ct); |
| 186 | }); |
| 187 | |
| 188 | bot.OnMessage("(?i)^logout graph$", async (context, ct) => |
| 189 | { |
| 190 | await graphAuth.SignOutAsync(context, ct); |
| 191 | await context.SendActivityAsync("Signed out from Graph.", ct); |
| 192 | }); |
| 193 | |
| 194 | bot.OnMessage("(?i)^logout github$", async (context, ct) => |
| 195 | { |
| 196 | await githubAuth.SignOutAsync(context, ct); |
| 197 | await context.SendActivityAsync("Signed out from GitHub.", ct); |
| 198 | }); |
| 199 | |
| 200 | // ==================== INSTALL HANDLER ==================== |
| 201 | |
| 202 | bot.OnInstall(async (context, ct) => |
| 203 | { |
| 204 | await context.SendActivityAsync( |
| 205 | new MessageActivity("Welcome to the **OAuthFlow Bot**! Type `help` to see available commands.") |
| 206 | { |
| 207 | TextFormat = TextFormats.Markdown |
| 208 | }, ct); |
| 209 | }); |
| 210 | |
| 211 | webApp.Run(); |
| 212 | |