or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced.mdasync.mdazure-platform.mdcore-credentials.mddeveloper.mdindex.mdinteractive.mdservice-principal.md

service-principal.mddocs/

0

# Service Principal Credentials

1

2

Authenticate applications and services using Azure Active Directory service principals. Service principals are non-interactive identities that represent applications, enabling secure authentication without user interaction. These credentials support client secrets, X.509 certificates, and custom client assertions.

3

4

## Capabilities

5

6

### ClientSecretCredential

7

8

Authenticates a service principal using a client secret. This is the most common form of service principal authentication, suitable for applications that can securely store secrets.

9

10

```python { .api }

11

class ClientSecretCredential:

12

def __init__(

13

self,

14

tenant_id: str,

15

client_id: str,

16

client_secret: str,

17

*,

18

authority: Optional[str] = None,

19

cache_persistence_options: Optional[TokenCachePersistenceOptions] = None,

20

disable_instance_discovery: bool = False,

21

additionally_allowed_tenants: List[str] = None,

22

**kwargs

23

):

24

"""

25

Create a ClientSecretCredential for service principal authentication.

26

27

Args:

28

tenant_id: ID of the service principal's tenant (directory ID)

29

client_id: The service principal's client ID (application ID)

30

client_secret: One of the service principal's client secrets

31

authority: Authority of a Microsoft Entra endpoint. Default: login.microsoftonline.com

32

cache_persistence_options: Configuration for persistent token caching

33

disable_instance_discovery: Disable instance discovery and authority validation

34

additionally_allowed_tenants: Additional allowed tenants beyond the configured tenant

35

"""

36

37

def get_token(self, *scopes: str, claims: Optional[str] = None, tenant_id: Optional[str] = None, **kwargs) -> AccessToken:

38

"""

39

Request an access token for the specified scopes.

40

41

Args:

42

*scopes: Desired scopes for the access token

43

claims: Additional claims required in the token

44

tenant_id: Optional tenant ID override

45

46

Returns:

47

AccessToken: The access token with expiration information

48

49

Raises:

50

ClientAuthenticationError: Authentication failed due to invalid credentials

51

"""

52

53

def get_token_info(self, *scopes: str, options: Optional[dict] = None) -> dict:

54

"""

55

Request access token with additional information.

56

57

Args:

58

*scopes: Desired scopes for the access token

59

options: Additional options for token acquisition

60

61

Returns:

62

dict: Token information including access token and metadata

63

"""

64

```

65

66

**Usage Example:**

67

68

```python

69

from azure.identity import ClientSecretCredential

70

from azure.keyvault.secrets import SecretClient

71

72

# Create service principal credential

73

credential = ClientSecretCredential(

74

tenant_id="your-tenant-id",

75

client_id="your-client-id",

76

client_secret="your-client-secret"

77

)

78

79

# Use with Azure SDK client

80

secret_client = SecretClient(

81

vault_url="https://vault.vault.azure.net/",

82

credential=credential

83

)

84

85

# Multi-tenant configuration

86

multi_tenant_credential = ClientSecretCredential(

87

tenant_id="primary-tenant-id",

88

client_id="your-client-id",

89

client_secret="your-client-secret",

90

additionally_allowed_tenants=["tenant-2", "tenant-3"]

91

)

92

```

93

94

### CertificateCredential

95

96

Authenticates a service principal using an X.509 certificate. More secure than client secrets as certificates can be stored in secure hardware and have expiration dates.

97

98

```python { .api }

99

class CertificateCredential:

100

def __init__(

101

self,

102

tenant_id: str,

103

client_id: str,

104

certificate_path: Optional[str] = None,

105

*,

106

authority: Optional[str] = None,

107

certificate_data: Optional[bytes] = None,

108

password: Optional[Union[str, bytes]] = None,

109

send_certificate_chain: bool = False,

110

cache_persistence_options: Optional[TokenCachePersistenceOptions] = None,

111

disable_instance_discovery: bool = False,

112

additionally_allowed_tenants: List[str] = None,

113

**kwargs

114

):

115

"""

116

Create a CertificateCredential for certificate-based service principal authentication.

117

118

Args:

119

tenant_id: ID of the service principal's tenant

120

client_id: The service principal's client ID

121

certificate_path: Path to a certificate file in PEM or PKCS12 format

122

authority: Authority of a Microsoft Entra endpoint

123

certificate_data: The bytes of a certificate in PEM or PKCS12 format (alternative to certificate_path)

124

password: The certificate's password (for PKCS12 certificates)

125

send_certificate_chain: Send the complete public certificate chain in x5c header

126

cache_persistence_options: Configuration for persistent token caching

127

disable_instance_discovery: Disable instance discovery and authority validation

128

additionally_allowed_tenants: Additional allowed tenants beyond the configured tenant

129

"""

130

131

def get_token(self, *scopes: str, claims: Optional[str] = None, tenant_id: Optional[str] = None, **kwargs) -> AccessToken:

132

"""

133

Request an access token for the specified scopes using certificate authentication.

134

135

Args:

136

*scopes: Desired scopes for the access token

137

claims: Additional claims required in the token

138

tenant_id: Optional tenant ID override

139

140

Returns:

141

AccessToken: The access token with expiration information

142

143

Raises:

144

ClientAuthenticationError: Authentication failed due to invalid certificate

145

ValueError: Certificate path and data both provided or neither provided

146

"""

147

148

def get_token_info(self, *scopes: str, options: Optional[dict] = None) -> dict:

149

"""

150

Request access token with additional information.

151

152

Args:

153

*scopes: Desired scopes for the access token

154

options: Additional options for token acquisition

155

156

Returns:

157

dict: Token information including access token and metadata

158

"""

159

```

160

161

**Usage Example:**

162

163

```python

164

from azure.identity import CertificateCredential

165

166

# Certificate from file path

167

credential = CertificateCredential(

168

tenant_id="your-tenant-id",

169

client_id="your-client-id",

170

certificate_path="/path/to/certificate.pem"

171

)

172

173

# Certificate with password (PKCS12)

174

p12_credential = CertificateCredential(

175

tenant_id="your-tenant-id",

176

client_id="your-client-id",

177

certificate_path="/path/to/certificate.p12",

178

password="certificate-password"

179

)

180

181

# Certificate from bytes (loaded from secure storage)

182

with open("/path/to/certificate.pem", "rb") as cert_file:

183

cert_data = cert_file.read()

184

185

data_credential = CertificateCredential(

186

tenant_id="your-tenant-id",

187

client_id="your-client-id",

188

certificate_data=cert_data

189

)

190

191

# Include full certificate chain for validation

192

chain_credential = CertificateCredential(

193

tenant_id="your-tenant-id",

194

client_id="your-client-id",

195

certificate_path="/path/to/certificate.pem",

196

send_certificate_chain=True

197

)

198

```

199

200

### ClientAssertionCredential

201

202

Authenticates a service principal using a signed client assertion (JWT). Provides the most flexibility for custom authentication scenarios and integration with hardware security modules (HSMs) or custom signing mechanisms.

203

204

```python { .api }

205

class ClientAssertionCredential:

206

def __init__(

207

self,

208

tenant_id: str,

209

client_id: str,

210

func: Callable[[], str],

211

*,

212

authority: Optional[str] = None,

213

cache_persistence_options: Optional[TokenCachePersistenceOptions] = None,

214

disable_instance_discovery: bool = False,

215

additionally_allowed_tenants: List[str] = None,

216

**kwargs

217

):

218

"""

219

Create a ClientAssertionCredential for custom assertion-based authentication.

220

221

Args:

222

tenant_id: ID of the application's Microsoft Entra tenant

223

client_id: The application's client ID

224

func: A callable that returns a client assertion (signed JWT)

225

authority: Authority of a Microsoft Entra endpoint

226

cache_persistence_options: Configuration for persistent token caching

227

disable_instance_discovery: Disable instance discovery and authority validation

228

additionally_allowed_tenants: Additional allowed tenants beyond the configured tenant

229

230

Note:

231

The func callable must return a valid JWT client assertion each time it's called.

232

The assertion must be signed with the application's registered certificate or key.

233

"""

234

235

def get_token(self, *scopes: str, claims: Optional[str] = None, tenant_id: Optional[str] = None, **kwargs) -> AccessToken:

236

"""

237

Request an access token using the client assertion.

238

239

Args:

240

*scopes: Desired scopes for the access token

241

claims: Additional claims required in the token

242

tenant_id: Optional tenant ID override

243

244

Returns:

245

AccessToken: The access token with expiration information

246

247

Raises:

248

ClientAuthenticationError: Authentication failed due to invalid assertion

249

"""

250

251

def get_token_info(self, *scopes: str, options: Optional[dict] = None) -> dict:

252

"""

253

Request access token with additional information.

254

255

Args:

256

*scopes: Desired scopes for the access token

257

options: Additional options for token acquisition

258

259

Returns:

260

dict: Token information including access token and metadata

261

"""

262

```

263

264

**Usage Example:**

265

266

```python

267

from azure.identity import ClientAssertionCredential

268

import jwt

269

import time

270

271

def create_client_assertion():

272

"""Create a signed JWT client assertion."""

273

now = int(time.time())

274

payload = {

275

'aud': f'https://login.microsoftonline.com/{tenant_id}/v2.0',

276

'exp': now + 600, # 10 minutes

277

'iss': client_id,

278

'jti': str(uuid.uuid4()), # unique identifier

279

'nbf': now,

280

'sub': client_id

281

}

282

283

# Sign with your private key

284

return jwt.encode(payload, private_key, algorithm='RS256')

285

286

# Create credential with custom assertion function

287

credential = ClientAssertionCredential(

288

tenant_id="your-tenant-id",

289

client_id="your-client-id",

290

func=create_client_assertion

291

)

292

293

# Use with Azure SDK

294

from azure.storage.blob import BlobServiceClient

295

296

blob_client = BlobServiceClient(

297

account_url="https://account.blob.core.windows.net",

298

credential=credential

299

)

300

```

301

302

### OnBehalfOfCredential

303

304

Implements the OAuth 2.0 On-Behalf-Of flow for middle-tier services that need to access downstream APIs on behalf of a user. Commonly used in multi-tier application architectures.

305

306

```python { .api }

307

class OnBehalfOfCredential:

308

def __init__(

309

self,

310

tenant_id: str,

311

client_id: str,

312

*,

313

client_secret: Optional[str] = None,

314

user_assertion: Optional[str] = None,

315

client_assertion: Optional[str] = None,

316

client_assertion_func: Optional[Callable[[], str]] = None,

317

authority: Optional[str] = None,

318

cache_persistence_options: Optional[TokenCachePersistenceOptions] = None,

319

disable_instance_discovery: bool = False,

320

additionally_allowed_tenants: List[str] = None,

321

**kwargs

322

):

323

"""

324

Create an OnBehalfOfCredential for on-behalf-of authentication flow.

325

326

Args:

327

tenant_id: ID of the application's Microsoft Entra tenant

328

client_id: The application's client ID

329

client_secret: One of the application's client secrets (mutually exclusive with client_assertion)

330

user_assertion: The access token the application will use to authenticate on behalf of the user

331

client_assertion: Signed client assertion (mutually exclusive with client_secret)

332

client_assertion_func: Function that returns a client assertion

333

authority: Authority of a Microsoft Entra endpoint

334

cache_persistence_options: Configuration for persistent token caching

335

disable_instance_discovery: Disable instance discovery and authority validation

336

additionally_allowed_tenants: Additional allowed tenants beyond the configured tenant

337

338

Note:

339

Either client_secret or client_assertion (or client_assertion_func) must be provided.

340

The user_assertion is typically obtained from the incoming request's Authorization header.

341

"""

342

343

def get_token(self, *scopes: str, claims: Optional[str] = None, tenant_id: Optional[str] = None, **kwargs) -> AccessToken:

344

"""

345

Request an access token on behalf of a user.

346

347

Args:

348

*scopes: Desired scopes for the access token

349

claims: Additional claims required in the token

350

tenant_id: Optional tenant ID override

351

352

Returns:

353

AccessToken: The access token with expiration information

354

355

Raises:

356

ClientAuthenticationError: Authentication failed

357

"""

358

359

def get_token_info(self, *scopes: str, options: Optional[dict] = None) -> dict:

360

"""

361

Request access token with additional information.

362

363

Args:

364

*scopes: Desired scopes for the access token

365

options: Additional options for token acquisition

366

367

Returns:

368

dict: Token information including access token and metadata

369

"""

370

```

371

372

**Usage Example:**

373

374

```python

375

from azure.identity import OnBehalfOfCredential

376

from flask import Flask, request

377

378

app = Flask(__name__)

379

380

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

381

def get_data():

382

# Extract user token from Authorization header

383

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

384

user_token = auth_header.replace('Bearer ', '') if auth_header else None

385

386

# Create OBO credential

387

credential = OnBehalfOfCredential(

388

tenant_id="your-tenant-id",

389

client_id="your-client-id",

390

client_secret="your-client-secret",

391

user_assertion=user_token

392

)

393

394

# Use credential to access downstream API on behalf of user

395

from azure.storage.blob import BlobServiceClient

396

397

blob_client = BlobServiceClient(

398

account_url="https://account.blob.core.windows.net",

399

credential=credential

400

)

401

402

# Access user's data

403

containers = blob_client.list_containers()

404

return [c.name for c in containers]

405

```

406

407

### AuthorizationCodeCredential

408

409

Authenticates by redeeming an authorization code previously obtained from Microsoft Entra ID. Used in OAuth 2.0 authorization code flow scenarios, typically in web applications.

410

411

```python { .api }

412

class AuthorizationCodeCredential:

413

def __init__(

414

self,

415

tenant_id: str,

416

client_id: str,

417

authorization_code: str,

418

redirect_uri: str,

419

*,

420

client_secret: Optional[str] = None,

421

authority: Optional[str] = None,

422

cache_persistence_options: Optional[TokenCachePersistenceOptions] = None,

423

disable_instance_discovery: bool = False,

424

additionally_allowed_tenants: List[str] = None,

425

**kwargs

426

):

427

"""

428

Create an AuthorizationCodeCredential for authorization code flow.

429

430

Args:

431

tenant_id: ID of the application's Microsoft Entra tenant

432

client_id: The application's client ID

433

authorization_code: The authorization code from the user's log-in

434

redirect_uri: The application's redirect URI (must match registered URI)

435

client_secret: One of the application's client secrets (required for confidential clients)

436

authority: Authority of a Microsoft Entra endpoint

437

cache_persistence_options: Configuration for persistent token caching

438

disable_instance_discovery: Disable instance discovery and authority validation

439

additionally_allowed_tenants: Additional allowed tenants beyond the configured tenant

440

"""

441

442

def get_token(self, *scopes: str, claims: Optional[str] = None, tenant_id: Optional[str] = None, **kwargs) -> AccessToken:

443

"""

444

Redeem the authorization code for an access token.

445

446

Args:

447

*scopes: Desired scopes for the access token

448

claims: Additional claims required in the token

449

tenant_id: Optional tenant ID override

450

451

Returns:

452

AccessToken: The access token with expiration information

453

454

Raises:

455

ClientAuthenticationError: Invalid authorization code or credentials

456

"""

457

458

def get_token_info(self, *scopes: str, options: Optional[dict] = None) -> dict:

459

"""

460

Request access token with additional information.

461

462

Args:

463

*scopes: Desired scopes for the access token

464

options: Additional options for token acquisition

465

466

Returns:

467

dict: Token information including access token and metadata

468

"""

469

```

470

471

**Usage Example:**

472

473

```python

474

from azure.identity import AuthorizationCodeCredential

475

from flask import Flask, request, redirect, session

476

477

app = Flask(__name__)

478

479

@app.route('/login')

480

def login():

481

# Redirect to Microsoft Entra ID for authorization

482

auth_url = (

483

f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/authorize"

484

f"?client_id={client_id}"

485

f"&response_type=code"

486

f"&redirect_uri={redirect_uri}"

487

f"&scope=https://graph.microsoft.com/.default"

488

)

489

return redirect(auth_url)

490

491

@app.route('/callback')

492

def callback():

493

# Extract authorization code from callback

494

code = request.args.get('code')

495

496

# Create credential with authorization code

497

credential = AuthorizationCodeCredential(

498

tenant_id="your-tenant-id",

499

client_id="your-client-id",

500

authorization_code=code,

501

redirect_uri="http://localhost:5000/callback",

502

client_secret="your-client-secret"

503

)

504

505

# Store credential in session for subsequent requests

506

session['credential'] = credential

507

return "Authentication successful!"

508

```

509

510

## Common Configuration

511

512

All service principal credentials support these common configuration options:

513

514

```python { .api }

515

# Multi-tenant configuration

516

additionally_allowed_tenants: List[str] = None

517

518

# Authority customization

519

authority: str = "https://login.microsoftonline.com" # Public cloud (default)

520

# authority: str = "https://login.chinacloudapi.cn" # Azure China

521

# authority: str = "https://login.microsoftonline.us" # Azure Government

522

523

# Token caching

524

cache_persistence_options: Optional[TokenCachePersistenceOptions] = None

525

526

# Instance discovery (for custom domains)

527

disable_instance_discovery: bool = False

528

529

# Logging and debugging

530

enable_support_logging: bool = False

531

```