or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

activity-handling.mdbot-adapters.mdindex.mdmessage-factories.mdmiddleware.mdoauth-authentication.mdstate-management.mdstorage.mdtelemetry-logging.mdtesting-utilities.mdturn-context.md

oauth-authentication.mddocs/

0

# OAuth & Authentication

1

2

OAuth token management and user authentication functionality. Includes token providers, authentication utilities, and integration with Bot Framework authentication services.

3

4

## Capabilities

5

6

### ExtendedUserTokenProvider

7

8

Extended user token provider interface that provides comprehensive OAuth token management capabilities including token retrieval, sign-out, and token exchange functionality.

9

10

```python { .api }

11

class ExtendedUserTokenProvider:

12

async def get_user_token(self, turn_context: TurnContext, connection_name: str, magic_code: str = None, oauth_app_credentials=None):

13

"""

14

Get OAuth token for user.

15

16

Args:

17

turn_context (TurnContext): Current turn context

18

connection_name (str): OAuth connection name

19

magic_code (str, optional): Magic code from OAuth flow

20

oauth_app_credentials (optional): OAuth app credentials

21

22

Returns:

23

TokenResponse: Token response or None

24

"""

25

26

async def sign_out_user(self, turn_context: TurnContext, connection_name: str, user_id: str = None, oauth_app_credentials=None):

27

"""

28

Sign out user from OAuth provider.

29

30

Args:

31

turn_context (TurnContext): Current turn context

32

connection_name (str): OAuth connection name

33

user_id (str, optional): User ID to sign out

34

oauth_app_credentials (optional): OAuth app credentials

35

"""

36

37

async def get_oauth_sign_in_link(self, turn_context: TurnContext, connection_name: str, oauth_app_credentials=None, final_redirect: str = None):

38

"""

39

Get OAuth sign-in link.

40

41

Args:

42

turn_context (TurnContext): Current turn context

43

connection_name (str): OAuth connection name

44

oauth_app_credentials (optional): OAuth app credentials

45

final_redirect (str, optional): Final redirect URL

46

47

Returns:

48

str: OAuth sign-in URL

49

"""

50

51

async def exchange_token(self, turn_context: TurnContext, connection_name: str, user_id: str, exchange_request):

52

"""

53

Exchange token with OAuth provider.

54

55

Args:

56

turn_context (TurnContext): Current turn context

57

connection_name (str): OAuth connection name

58

user_id (str): User ID

59

exchange_request: Token exchange request

60

61

Returns:

62

TokenResponse: Exchange response

63

"""

64

```

65

66

### UserTokenProvider

67

68

Base user token provider interface that defines the core OAuth functionality for token management in bot applications.

69

70

```python { .api }

71

class UserTokenProvider:

72

async def get_user_token(self, turn_context: TurnContext, connection_name: str, magic_code: str = None):

73

"""Get user token from OAuth provider."""

74

75

async def sign_out_user(self, turn_context: TurnContext, connection_name: str, user_id: str = None):

76

"""Sign out user from OAuth provider."""

77

78

async def get_oauth_sign_in_link(self, turn_context: TurnContext, connection_name: str):

79

"""Get OAuth sign-in link."""

80

```

81

82

### ConnectorClientBuilder

83

84

Abstract base class for building connector clients with authentication support for Bot Framework communication.

85

86

```python { .api }

87

class ConnectorClientBuilder:

88

async def create_connector_client(self, service_url: str, identity=None, audience: str = None):

89

"""

90

Create connector client with authentication.

91

92

Args:

93

service_url (str): Service URL

94

identity (optional): Claims identity

95

audience (str, optional): Target audience

96

97

Returns:

98

ConnectorClient: Authenticated connector client

99

"""

100

```

101

102

## Usage Examples

103

104

### Basic OAuth Flow

105

106

```python

107

from botbuilder.core import ActivityHandler, TurnContext, MessageFactory, CardFactory

108

109

class OAuthBot(ActivityHandler):

110

def __init__(self, connection_name: str):

111

self.connection_name = connection_name

112

113

async def on_message_activity(self, turn_context: TurnContext):

114

text = turn_context.activity.text.lower()

115

116

if text in ["login", "signin"]:

117

await self.send_oauth_card(turn_context)

118

elif text in ["logout", "signout"]:

119

await self.sign_out_user(turn_context)

120

elif text == "profile":

121

await self.show_user_profile(turn_context)

122

else:

123

await turn_context.send_activity(MessageFactory.text("Say 'login' to authenticate"))

124

125

async def on_token_response_event(self, turn_context: TurnContext):

126

# Handle successful OAuth token response

127

token_response = turn_context.activity.value

128

if token_response and token_response.get("token"):

129

await turn_context.send_activity(MessageFactory.text("Authentication successful!"))

130

await self.show_user_profile(turn_context)

131

else:

132

await turn_context.send_activity(MessageFactory.text("Authentication failed"))

133

134

async def send_oauth_card(self, turn_context: TurnContext):

135

# Create OAuth card

136

card = CardFactory.oauth_card(

137

connection_name=self.connection_name,

138

title="Please sign in",

139

text="Click below to sign in with your account"

140

)

141

142

reply = MessageFactory.attachment(card)

143

await turn_context.send_activity(reply)

144

145

async def sign_out_user(self, turn_context: TurnContext):

146

# Get the adapter (assumes it implements ExtendedUserTokenProvider)

147

adapter = turn_context.adapter

148

149

await adapter.sign_out_user(turn_context, self.connection_name)

150

await turn_context.send_activity(MessageFactory.text("You have been signed out"))

151

152

async def show_user_profile(self, turn_context: TurnContext):

153

# Get user token

154

adapter = turn_context.adapter

155

token_response = await adapter.get_user_token(turn_context, self.connection_name)

156

157

if token_response:

158

# Use token to call external API (example with Microsoft Graph)

159

user_info = await self.get_user_info_from_graph(token_response.token)

160

await turn_context.send_activity(

161

MessageFactory.text(f"Hello {user_info.get('displayName', 'User')}!")

162

)

163

else:

164

await self.send_oauth_card(turn_context)

165

166

async def get_user_info_from_graph(self, token: str):

167

# Example: Call Microsoft Graph API

168

import aiohttp

169

170

headers = {"Authorization": f"Bearer {token}"}

171

async with aiohttp.ClientSession() as session:

172

async with session.get("https://graph.microsoft.com/v1.0/me", headers=headers) as response:

173

if response.status == 200:

174

return await response.json()

175

return {}

176

```

177

178

### Magic Code Flow

179

180

```python

181

async def on_message_activity(self, turn_context: TurnContext):

182

text = turn_context.activity.text

183

184

# Check if message contains magic code (6-digit number)

185

if text.isdigit() and len(text) == 6:

186

await self.process_magic_code(turn_context, text)

187

else:

188

await self.send_oauth_card(turn_context)

189

190

async def process_magic_code(self, turn_context: TurnContext, magic_code: str):

191

adapter = turn_context.adapter

192

193

# Try to get token using magic code

194

token_response = await adapter.get_user_token(

195

turn_context,

196

self.connection_name,

197

magic_code=magic_code

198

)

199

200

if token_response:

201

await turn_context.send_activity(MessageFactory.text("Authentication successful with magic code!"))

202

await self.show_user_profile(turn_context)

203

else:

204

await turn_context.send_activity(MessageFactory.text("Invalid magic code. Please try again."))

205

await self.send_oauth_card(turn_context)

206

```

207

208

### Token Exchange

209

210

```python

211

async def handle_token_exchange(self, turn_context: TurnContext, sso_token: str):

212

adapter = turn_context.adapter

213

214

# Create token exchange request

215

exchange_request = {

216

"token": sso_token,

217

"uri": "https://graph.microsoft.com/.default"

218

}

219

220

# Exchange SSO token for access token

221

token_response = await adapter.exchange_token(

222

turn_context,

223

self.connection_name,

224

turn_context.activity.from_property.id,

225

exchange_request

226

)

227

228

if token_response:

229

await turn_context.send_activity(MessageFactory.text("Token exchange successful!"))

230

# Use the exchanged token

231

await self.use_access_token(token_response.token)

232

else:

233

await turn_context.send_activity(MessageFactory.text("Token exchange failed"))

234

await self.send_oauth_card(turn_context)

235

```

236

237

## Types

238

239

```python { .api }

240

class TokenResponse:

241

"""OAuth token response."""

242

def __init__(self):

243

self.channel_id: str = None

244

self.connection_name: str = None

245

self.token: str = None

246

self.expiration: str = None

247

248

class TokenExchangeRequest:

249

"""Token exchange request."""

250

def __init__(self):

251

self.uri: str = None

252

self.token: str = None

253

254

class OAuthCard:

255

"""OAuth card for authentication."""

256

def __init__(self):

257

self.text: str = None

258

self.connection_name: str = None

259

self.buttons: list = None

260

```