or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-authentication-flows.mdauthorization-code-authentication.mdazure-developer-cli-authentication.mdazure-pipelines-authentication.mdclient-assertion-authentication.mdconfiguration-and-utilities.mdcredential-chaining.mddefault-azure-credential.mddeveloper-tool-credentials.mdenvironment-credential.mdindex.mdinteractive-user-authentication.mdmanaged-identity-credential.mdservice-principal-authentication.mdshared-token-cache-authentication.mdusername-password-authentication.mdvisual-studio-code-authentication.md

credential-chaining.mddocs/

0

# Credential Chaining

1

2

Credential chaining allows you to combine multiple TokenCredential implementations, attempting each in sequence until one successfully authenticates. This pattern enables robust authentication strategies that work across different environments and scenarios.

3

4

## Basic Chaining

5

6

```java

7

import com.azure.identity.ChainedTokenCredential;

8

import com.azure.identity.ChainedTokenCredentialBuilder;

9

10

// Create a custom credential chain

11

TokenCredential chainedCredential = new ChainedTokenCredentialBuilder()

12

.addLast(new ManagedIdentityCredentialBuilder().build())

13

.addLast(new AzureCliCredentialBuilder().build())

14

.addLast(new EnvironmentCredentialBuilder().build())

15

.build();

16

17

// Use with Azure SDK client

18

BlobServiceClient client = new BlobServiceClientBuilder()

19

.endpoint("https://mystorageaccount.blob.core.windows.net/")

20

.credential(chainedCredential)

21

.buildClient();

22

```

23

24

## Development vs Production Chain

25

26

```java

27

// Development-focused chain

28

TokenCredential devChain = new ChainedTokenCredentialBuilder()

29

.addLast(new AzureCliCredentialBuilder().build())

30

.addLast(new AzurePowerShellCredentialBuilder().build())

31

.addLast(new IntelliJCredentialBuilder().build())

32

.addLast(new VisualStudioCodeCredentialBuilder().build())

33

.build();

34

35

// Production-focused chain

36

TokenCredential prodChain = new ChainedTokenCredentialBuilder()

37

.addLast(new ManagedIdentityCredentialBuilder().build())

38

.addLast(new EnvironmentCredentialBuilder().build())

39

.addLast(new ClientSecretCredentialBuilder()

40

.tenantId(System.getenv("AZURE_TENANT_ID"))

41

.clientId(System.getenv("AZURE_CLIENT_ID"))

42

.clientSecret(System.getenv("AZURE_CLIENT_SECRET"))

43

.build())

44

.build();

45

```

46

47

## Environment-Aware Chaining

48

49

```java

50

// Conditional chain based on environment

51

public static TokenCredential createCredential() {

52

String environment = System.getenv("ENVIRONMENT");

53

54

if ("development".equals(environment)) {

55

return new ChainedTokenCredentialBuilder()

56

.addLast(new AzureCliCredentialBuilder().build())

57

.addLast(new IntelliJCredentialBuilder().build())

58

.build();

59

} else if ("production".equals(environment)) {

60

return new ChainedTokenCredentialBuilder()

61

.addLast(new ManagedIdentityCredentialBuilder().build())

62

.addLast(new EnvironmentCredentialBuilder().build())

63

.build();

64

} else {

65

// Default chain for unknown environments

66

return new DefaultAzureCredentialBuilder().build();

67

}

68

}

69

```

70

71

## Fallback Strategies

72

73

```java

74

// Primary credential with multiple fallbacks

75

TokenCredential robustCredential = new ChainedTokenCredentialBuilder()

76

// Primary: Managed Identity (for Azure-hosted apps)

77

.addLast(new ManagedIdentityCredentialBuilder().build())

78

79

// Fallback 1: Environment variables (for containerized apps)

80

.addLast(new EnvironmentCredentialBuilder().build())

81

82

// Fallback 2: Service principal with certificate

83

.addLast(new ClientCertificateCredentialBuilder()

84

.tenantId("tenant-id")

85

.clientId("client-id")

86

.pfxCertificate("path/to/cert.pfx", "password")

87

.build())

88

89

// Fallback 3: Interactive browser (for development)

90

.addLast(new InteractiveBrowserCredentialBuilder()

91

.redirectUrl("http://localhost:8765")

92

.build())

93

94

.build();

95

```

96

97

## Credential Ordering Best Practices

98

99

```java

100

// Recommended ordering: Most secure/reliable first, interactive last

101

TokenCredential wellOrderedChain = new ChainedTokenCredentialBuilder()

102

// 1. Managed Identity - Most secure for Azure environments

103

.addLast(new ManagedIdentityCredentialBuilder().build())

104

105

// 2. Environment variables - Good for containerized environments

106

.addLast(new EnvironmentCredentialBuilder().build())

107

108

// 3. Service principal with certificate - More secure than secret

109

.addLast(new ClientCertificateCredentialBuilder()

110

.tenantId("tenant-id")

111

.clientId("client-id")

112

.pfxCertificate("cert.pfx", "password")

113

.build())

114

115

// 4. Developer tools - Good for local development

116

.addLast(new AzureCliCredentialBuilder().build())

117

.addLast(new AzurePowerShellCredentialBuilder().build())

118

119

// 5. Interactive credentials - Last resort requiring user interaction

120

.addLast(new DeviceCodeCredentialBuilder().build())

121

122

.build();

123

```

124

125

## Custom Credential Implementation

126

127

```java

128

// Custom credential that implements specific logic

129

public class CustomCredential implements TokenCredential {

130

@Override

131

public Mono<AccessToken> getToken(TokenRequestContext request) {

132

// Custom authentication logic

133

if (someCondition()) {

134

return authenticateWithCustomMethod(request);

135

} else {

136

return Mono.error(new CredentialUnavailableException("Custom credential not available"));

137

}

138

}

139

140

private Mono<AccessToken> authenticateWithCustomMethod(TokenRequestContext request) {

141

// Implementation details

142

return Mono.just(new AccessToken("token", OffsetDateTime.now().plusHours(1)));

143

}

144

}

145

146

// Use custom credential in chain

147

TokenCredential chainWithCustom = new ChainedTokenCredentialBuilder()

148

.addLast(new ManagedIdentityCredentialBuilder().build())

149

.addLast(new CustomCredential())

150

.addLast(new EnvironmentCredentialBuilder().build())

151

.build();

152

```

153

154

## Error Handling in Chains

155

156

```java

157

try {

158

ChainedTokenCredential credential = new ChainedTokenCredentialBuilder()

159

.addLast(new ManagedIdentityCredentialBuilder().build())

160

.addLast(new AzureCliCredentialBuilder().build())

161

.build();

162

163

AccessToken token = credential.getTokenSync(

164

new TokenRequestContext().addScopes("https://management.azure.com/.default")

165

);

166

167

System.out.println("Authentication successful with chained credential");

168

169

} catch (CredentialUnavailableException e) {

170

System.err.println("All credentials in chain failed: " + e.getMessage());

171

// This means none of the credentials in the chain were able to authenticate

172

} catch (ClientAuthenticationException e) {

173

System.err.println("Authentication error: " + e.getMessage());

174

// One of the credentials attempted authentication but failed

175

}

176

```

177

178

## Debugging Credential Chains

179

180

```java

181

// Enable logging to see which credentials are being tried

182

TokenCredential debugChain = new ChainedTokenCredentialBuilder()

183

.addLast(new ManagedIdentityCredentialBuilder()

184

.enableAccountIdentifierLogging() // Enable account logging

185

.build())

186

.addLast(new AzureCliCredentialBuilder()

187

.enableAccountIdentifierLogging()

188

.build())

189

.build();

190

191

// Configure logging in your application to see credential attempts

192

// Add to logging.properties or logback.xml:

193

// com.azure.identity=DEBUG

194

```

195

196

## Performance Considerations

197

198

```java

199

// Optimize chain order for performance

200

TokenCredential optimizedChain = new ChainedTokenCredentialBuilder()

201

// Fast credentials first

202

.addLast(new ManagedIdentityCredentialBuilder().build()) // Very fast in Azure

203

.addLast(new EnvironmentCredentialBuilder().build()) // Fast environment lookup

204

205

// Slower credentials later

206

.addLast(new AzureCliCredentialBuilder().build()) // Subprocess call

207

.addLast(new InteractiveBrowserCredentialBuilder() // User interaction required

208

.redirectUrl("http://localhost:8765")

209

.build())

210

211

.build();

212

```

213

214

## API Reference

215

216

```java { .api }

217

class ChainedTokenCredential implements TokenCredential {

218

Mono<AccessToken> getToken(TokenRequestContext request);

219

AccessToken getTokenSync(TokenRequestContext request);

220

}

221

222

class ChainedTokenCredentialBuilder {

223

ChainedTokenCredentialBuilder addLast(TokenCredential credential);

224

ChainedTokenCredential build();

225

}

226

```

227

228

## Advanced Chaining Patterns

229

230

```java

231

// Conditional chaining based on environment variables

232

public class EnvironmentAwareCredentialChain {

233

public static TokenCredential create() {

234

ChainedTokenCredentialBuilder builder = new ChainedTokenCredentialBuilder();

235

236

// Always try managed identity first in Azure environments

237

if (isRunningInAzure()) {

238

builder.addLast(new ManagedIdentityCredentialBuilder().build());

239

}

240

241

// Add environment credential if variables are present

242

if (hasEnvironmentCredentials()) {

243

builder.addLast(new EnvironmentCredentialBuilder().build());

244

}

245

246

// Add developer tools in development mode

247

if (isDevelopmentMode()) {

248

builder.addLast(new AzureCliCredentialBuilder().build())

249

.addLast(new IntelliJCredentialBuilder().build());

250

}

251

252

// Fallback to interactive if nothing else works

253

if (isInteractiveMode()) {

254

builder.addLast(new InteractiveBrowserCredentialBuilder()

255

.redirectUrl("http://localhost:8765")

256

.build());

257

}

258

259

return builder.build();

260

}

261

262

private static boolean isRunningInAzure() {

263

return System.getenv("MSI_ENDPOINT") != null ||

264

System.getenv("IDENTITY_ENDPOINT") != null;

265

}

266

267

private static boolean hasEnvironmentCredentials() {

268

return System.getenv("AZURE_CLIENT_SECRET") != null ||

269

System.getenv("AZURE_CLIENT_CERTIFICATE_PATH") != null;

270

}

271

272

private static boolean isDevelopmentMode() {

273

return "development".equals(System.getenv("ENVIRONMENT"));

274

}

275

276

private static boolean isInteractiveMode() {

277

return System.console() != null;

278

}

279

}

280

```

281

282

## Best Practices

283

284

1. **Order by Reliability**: Place most reliable credentials first in the chain

285

2. **Environment-Specific Chains**: Create different chains for different deployment environments

286

3. **Fast Credentials First**: Order credentials by authentication speed for better performance

287

4. **Avoid Interactive in Production**: Don't include interactive credentials in production chains

288

5. **Handle All Failures**: Implement proper error handling for when all credentials fail

289

6. **Enable Logging**: Use logging to debug which credentials are being attempted

290

7. **Security First**: Prioritize more secure authentication methods (certificates over secrets)

291

8. **Minimize Chain Length**: Keep chains as short as possible while maintaining reliability

292

293

## Troubleshooting

294

295

Common issues with credential chains:

296

297

- **All Credentials Fail**: Ensure at least one credential type is properly configured

298

- **Slow Authentication**: Reorder chain to put faster credentials first

299

- **Interactive Prompts**: Remove interactive credentials for automated scenarios

300

- **Permission Errors**: Ensure all credentials have appropriate permissions

301

- **Environment Issues**: Verify environment variables and tool installations for each credential type