or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

common-auth-flows.mdconfidential-client.mdindex.mdmanaged-identity.mdpublic-client.mdsecurity-advanced.mdtoken-cache.md

confidential-client.mddocs/

0

# Confidential Client Applications

1

2

Confidential client applications are designed for server-side applications that can securely store credentials. MSAL Python's `ConfidentialClientApplication` supports client credentials flow for service-to-service authentication, authorization code flow for web applications, and on-behalf-of flow for middle-tier services.

3

4

## Capabilities

5

6

### Application Initialization

7

8

Creates a confidential client application with various credential types including client secrets, X.509 certificates, and Subject Name/Issuer authentication for certificate auto-rotation scenarios.

9

10

```python { .api }

11

class ConfidentialClientApplication(ClientApplication):

12

def __init__(

13

self,

14

client_id: str,

15

client_credential,

16

authority=None,

17

validate_authority=True,

18

token_cache=None,

19

http_client=None,

20

verify=True,

21

proxies=None,

22

timeout=None,

23

client_claims=None,

24

app_name=None,

25

app_version=None,

26

client_capabilities=None,

27

azure_region=None,

28

exclude_scopes=None,

29

http_cache=None,

30

instance_discovery=None,

31

enable_pii_log=None,

32

oidc_authority=None,

33

**kwargs

34

):

35

"""

36

Create a confidential client application.

37

38

Parameters:

39

- client_id: Your app's client ID from Azure portal

40

- client_credential: Client secret string, certificate dict, or assertion callable

41

- authority: Authority URL (default: https://login.microsoftonline.com/common)

42

- azure_region: Azure region for regional STS endpoints

43

- token_cache: Custom token cache instance

44

- http_client: Custom HTTP client

45

- proxies: HTTP proxy configuration

46

- timeout: HTTP timeout in seconds

47

"""

48

```

49

50

### Client Credential Types

51

52

#### Client Secret

53

```python

54

app = msal.ConfidentialClientApplication(

55

client_id="your-client-id",

56

client_credential="your-client-secret",

57

authority="https://login.microsoftonline.com/your-tenant-id"

58

)

59

```

60

61

#### X.509 Certificate

62

```python

63

client_credential = {

64

"private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",

65

"thumbprint": "A1B2C3D4E5F6...",

66

"passphrase": "optional-passphrase" # If private key is encrypted

67

}

68

69

app = msal.ConfidentialClientApplication(

70

client_id="your-client-id",

71

client_credential=client_credential,

72

authority="https://login.microsoftonline.com/your-tenant-id"

73

)

74

```

75

76

#### Subject Name/Issuer Authentication (Certificate Auto-rotation)

77

```python

78

client_credential = {

79

"private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",

80

"thumbprint": "A1B2C3D4E5F6...",

81

"public_certificate": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",

82

"passphrase": "optional-passphrase"

83

}

84

85

app = msal.ConfidentialClientApplication(

86

client_id="your-client-id",

87

client_credential=client_credential,

88

authority="https://login.microsoftonline.com/your-tenant-id"

89

)

90

```

91

92

### Client Credentials Flow

93

94

Acquires tokens for the application itself (not on behalf of a user) using client credentials. Commonly used for daemon applications and service-to-service authentication.

95

96

```python { .api }

97

def acquire_token_for_client(

98

self,

99

scopes: list,

100

claims_challenge=None,

101

**kwargs

102

):

103

"""

104

Acquire token for the client application.

105

106

Parameters:

107

- scopes: List of scopes (typically ["{resource}/.default"])

108

- claims_challenge: Additional claims from resource provider

109

110

Returns:

111

Dictionary with 'access_token' on success, 'error' on failure

112

"""

113

114

def remove_tokens_for_client(self):

115

"""

116

Remove all tokens previously acquired via acquire_token_for_client().

117

"""

118

```

119

120

Usage example:

121

122

```python

123

import msal

124

125

app = msal.ConfidentialClientApplication(

126

client_id="your-client-id",

127

client_credential="your-client-secret",

128

authority="https://login.microsoftonline.com/your-tenant-id"

129

)

130

131

# Acquire token for Microsoft Graph

132

result = app.acquire_token_for_client(

133

scopes=["https://graph.microsoft.com/.default"]

134

)

135

136

if "access_token" in result:

137

print("Client credentials authentication successful!")

138

access_token = result["access_token"]

139

140

# Use the token to call Microsoft Graph API

141

import requests

142

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

143

response = requests.get("https://graph.microsoft.com/v1.0/users", headers=headers)

144

145

if response.status_code == 200:

146

users = response.json()

147

print(f"Found {len(users.get('value', []))} users")

148

else:

149

print(f"Authentication failed: {result.get('error_description')}")

150

151

# Clear client tokens when needed

152

app.remove_tokens_for_client()

153

```

154

155

### On-Behalf-Of Flow

156

157

Allows middle-tier services to acquire tokens on behalf of users. The service uses a user's access token to request additional tokens for downstream APIs.

158

159

```python { .api }

160

def acquire_token_on_behalf_of(

161

self,

162

user_assertion: str,

163

scopes: list,

164

claims_challenge=None,

165

**kwargs

166

):

167

"""

168

Acquire token on behalf of user.

169

170

Parameters:

171

- user_assertion: The user's access token received by the service

172

- scopes: List of scopes for downstream API

173

- claims_challenge: Additional claims from resource provider

174

175

Returns:

176

Dictionary with 'access_token' on success, 'error' on failure

177

"""

178

```

179

180

Usage example:

181

182

```python

183

import msal

184

from flask import Flask, request

185

186

app_flask = Flask(__name__)

187

188

# Configure MSAL

189

msal_app = msal.ConfidentialClientApplication(

190

client_id="your-service-client-id",

191

client_credential="your-service-client-secret",

192

authority="https://login.microsoftonline.com/your-tenant-id"

193

)

194

195

@app_flask.route('/api/data')

196

def get_data():

197

# Extract user's access token from Authorization header

198

auth_header = request.headers.get('Authorization', '')

199

if not auth_header.startswith('Bearer '):

200

return {"error": "Missing or invalid authorization header"}, 401

201

202

user_token = auth_header[7:] # Remove 'Bearer ' prefix

203

204

# Use OBO flow to get token for downstream API

205

result = msal_app.acquire_token_on_behalf_of(

206

user_assertion=user_token,

207

scopes=["https://api.downstream.com/.default"]

208

)

209

210

if "access_token" in result:

211

# Call downstream API with new token

212

import requests

213

headers = {"Authorization": f"Bearer {result['access_token']}"}

214

response = requests.get("https://api.downstream.com/data", headers=headers)

215

return response.json()

216

else:

217

return {"error": result.get("error_description")}, 400

218

```

219

220

### Authorization Code Flow for Web Apps

221

222

Handles the authorization code flow for web applications, including PKCE (Proof Key for Code Exchange) support for enhanced security.

223

224

The authorization code flow is inherited from the base `ClientApplication` class:

225

226

```python { .api }

227

def initiate_auth_code_flow(

228

self,

229

scopes: list,

230

redirect_uri=None,

231

state=None,

232

prompt=None,

233

login_hint=None,

234

domain_hint=None,

235

claims_challenge=None,

236

max_age=None,

237

**kwargs

238

):

239

"""

240

Initiate authorization code flow.

241

242

Returns:

243

Dictionary containing auth_uri and state information

244

"""

245

246

def acquire_token_by_auth_code_flow(

247

self,

248

auth_code_flow: dict,

249

auth_response: dict,

250

scopes=None,

251

**kwargs

252

):

253

"""

254

Complete authorization code flow.

255

256

Parameters:

257

- auth_code_flow: Flow state from initiate_auth_code_flow()

258

- auth_response: Authorization response from redirect URI

259

- scopes: Optional scopes override

260

261

Returns:

262

Dictionary with 'access_token' on success, 'error' on failure

263

"""

264

```

265

266

Usage example for web application:

267

268

```python

269

import msal

270

from flask import Flask, request, redirect, session, url_for

271

272

app_flask = Flask(__name__)

273

app_flask.secret_key = 'your-secret-key'

274

275

msal_app = msal.ConfidentialClientApplication(

276

client_id="your-webapp-client-id",

277

client_credential="your-webapp-client-secret",

278

authority="https://login.microsoftonline.com/your-tenant-id"

279

)

280

281

@app_flask.route('/login')

282

def login():

283

# Initiate auth code flow

284

auth_flow = msal_app.initiate_auth_code_flow(

285

scopes=["User.Read"],

286

redirect_uri=url_for('auth_response', _external=True)

287

)

288

289

# Store flow state in session

290

session['auth_flow'] = auth_flow

291

292

# Redirect user to authorization URL

293

return redirect(auth_flow['auth_uri'])

294

295

@app_flask.route('/auth-response')

296

def auth_response():

297

# Get stored flow state

298

auth_flow = session.get('auth_flow', {})

299

300

# Complete the flow with authorization response

301

result = msal_app.acquire_token_by_auth_code_flow(

302

auth_code_flow=auth_flow,

303

auth_response=request.args

304

)

305

306

if "access_token" in result:

307

# Store tokens in session

308

session['tokens'] = result

309

return "Login successful!"

310

else:

311

return f"Login failed: {result.get('error_description')}"

312

```

313

314

### Azure Regional Endpoints

315

316

For applications deployed in Azure, use regional endpoints for improved performance and compliance:

317

318

```python

319

app = msal.ConfidentialClientApplication(

320

client_id="your-client-id",

321

client_credential="your-client-secret",

322

authority="https://login.microsoftonline.com/your-tenant-id",

323

azure_region="eastus" # Specify Azure region

324

)

325

326

# Or use auto-detection in Azure environment

327

app = msal.ConfidentialClientApplication(

328

client_id="your-client-id",

329

client_credential="your-client-secret",

330

authority="https://login.microsoftonline.com/your-tenant-id",

331

azure_region=msal.ClientApplication.ATTEMPT_REGION_DISCOVERY

332

)

333

```

334

335

## Error Handling

336

337

Common error scenarios and handling patterns:

338

339

```python

340

result = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])

341

342

if "access_token" in result:

343

# Success

344

access_token = result["access_token"]

345

expires_in = result["expires_in"]

346

elif result.get("error") == "invalid_client":

347

# Invalid client credentials

348

print("Invalid client ID or secret")

349

elif result.get("error") == "invalid_scope":

350

# Invalid or unauthorized scope

351

print(f"Invalid scope: {result.get('error_description')}")

352

elif result.get("error") == "unauthorized_client":

353

# Client not authorized for requested grant type

354

print("Client not authorized for client credentials flow")

355

else:

356

# Other error

357

print(f"Authentication failed: {result.get('error_description')}")

358

359

# Handle OBO-specific errors

360

obo_result = app.acquire_token_on_behalf_of(

361

user_assertion=user_token,

362

scopes=["https://api.downstream.com/.default"]

363

)

364

365

if obo_result.get("error") == "invalid_grant":

366

# User assertion is invalid or expired

367

print("User token is invalid or expired")

368

elif obo_result.get("error") == "consent_required":

369

# Additional consent needed

370

print("Additional consent required for downstream API")

371

```