or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

association-management.mdconsumer-auth.mddiscovery.mdextensions.mdindex.mdmessage-processing.mdserver-implementation.mdstorage-backends.mdutilities.md

consumer-auth.mddocs/

0

# Consumer Authentication

1

2

Complete OpenID consumer implementation for web applications acting as relying parties. The consumer handles the full authentication flow from discovery through response processing, supporting both immediate and setup authentication modes.

3

4

## Capabilities

5

6

### Consumer Initialization

7

8

Initialize an OpenID consumer with session storage and an OpenID store backend.

9

10

```python { .api }

11

class Consumer:

12

def __init__(self, session, store, consumer_class=None):

13

"""

14

Initialize OpenID consumer.

15

16

Parameters:

17

- session: dict-like session storage for the consumer

18

- store: OpenIDStore instance for persistent storage

19

- consumer_class: Optional custom consumer class (defaults to GenericConsumer)

20

"""

21

22

def setAssociationPreference(self, association_preferences):

23

"""

24

Set association preferences for this consumer.

25

26

Parameters:

27

- association_preferences: List of (association_type, session_type) tuples

28

"""

29

```

30

31

### Authentication Flow

32

33

Start and complete the OpenID authentication process with discovery and response handling.

34

35

```python { .api }

36

def begin(self, user_url, anonymous=False):

37

"""

38

Start OpenID authentication for a user URL.

39

40

Parameters:

41

- user_url: str, user's OpenID identifier URL

42

- anonymous: bool, whether to request anonymous authentication

43

44

Returns:

45

AuthRequest object for redirecting user to identity provider

46

47

Raises:

48

DiscoveryFailure: if discovery fails for the user URL

49

"""

50

51

def beginWithoutDiscovery(self, service, anonymous=False):

52

"""

53

Start authentication with a known service endpoint.

54

55

Parameters:

56

- service: OpenIDServiceEndpoint object

57

- anonymous: bool, whether to request anonymous authentication

58

59

Returns:

60

AuthRequest object

61

"""

62

63

def complete(self, query, current_url):

64

"""

65

Complete OpenID authentication from identity provider response.

66

67

Parameters:

68

- query: dict, query parameters from identity provider response

69

- current_url: str, current page URL for verification

70

71

Returns:

72

Response object (SuccessResponse, FailureResponse, CancelResponse, or SetupNeededResponse)

73

"""

74

```

75

76

### Authentication Request

77

78

Represents an OpenID authentication request that can be used to redirect users or generate HTML forms.

79

80

```python { .api }

81

class AuthRequest:

82

def setAnonymous(self, is_anonymous):

83

"""

84

Set whether this request should be anonymous.

85

86

Parameters:

87

- is_anonymous: bool, anonymous flag

88

"""

89

90

def addExtension(self, extension_request):

91

"""

92

Add an OpenID extension to this authentication request.

93

94

Parameters:

95

- extension_request: Extension request object (SRegRequest, FetchRequest, etc.)

96

"""

97

98

def addExtensionArg(self, namespace, key, value):

99

"""

100

Add an extension argument directly.

101

102

Parameters:

103

- namespace: str, extension namespace URI

104

- key: str, argument key

105

- value: str, argument value

106

"""

107

108

def getMessage(self, realm, return_to=None, immediate=False):

109

"""

110

Get the OpenID message for this request.

111

112

Parameters:

113

- realm: str, trust root/realm URL

114

- return_to: str, return URL after authentication

115

- immediate: bool, whether to use immediate mode

116

117

Returns:

118

Message object

119

"""

120

121

def redirectURL(self, realm, return_to=None, immediate=False):

122

"""

123

Get redirect URL for sending user to identity provider.

124

125

Parameters:

126

- realm: str, trust root/realm URL

127

- return_to: str, return URL after authentication

128

- immediate: bool, whether to use immediate mode

129

130

Returns:

131

str, redirect URL

132

"""

133

134

def formMarkup(self, realm, return_to=None, immediate=False, form_tag_attrs=None):

135

"""

136

Generate HTML form for POST-based authentication.

137

138

Parameters:

139

- realm: str, trust root/realm URL

140

- return_to: str, return URL after authentication

141

- immediate: bool, whether to use immediate mode

142

- form_tag_attrs: dict, additional HTML form attributes

143

144

Returns:

145

str, HTML form markup

146

"""

147

148

def htmlMarkup(self, realm, return_to=None, immediate=False, form_tag_attrs=None):

149

"""

150

Generate complete HTML page with auto-submitting form.

151

152

Parameters:

153

- realm: str, trust root/realm URL

154

- return_to: str, return URL after authentication

155

- immediate: bool, whether to use immediate mode

156

- form_tag_attrs: dict, additional HTML form attributes

157

158

Returns:

159

str, complete HTML page

160

"""

161

162

def shouldSendRedirect(self):

163

"""

164

Check if redirect should be used instead of POST form.

165

166

Returns:

167

bool, True if redirect is recommended

168

"""

169

```

170

171

### Response Handling

172

173

Process responses from identity providers with status checking and data extraction.

174

175

```python { .api }

176

class Response:

177

"""Base class for OpenID authentication responses."""

178

179

status = None

180

181

def setEndpoint(self, endpoint):

182

"""

183

Set the endpoint for this response.

184

185

Parameters:

186

- endpoint: OpenIDServiceEndpoint or None

187

"""

188

189

def getDisplayIdentifier(self):

190

"""

191

Return the display identifier for this response.

192

193

The display identifier is related to the Claimed Identifier, but the

194

two are not always identical. The display identifier is something the

195

user should recognize as what they entered, whereas the response's

196

claimed identifier may have extra information for better persistence.

197

198

Returns:

199

str or None, display identifier for user interface

200

"""

201

202

class SuccessResponse(Response):

203

"""Successful authentication response with status SUCCESS."""

204

205

def isOpenID1(self):

206

"""

207

Check if response uses OpenID 1.x protocol.

208

209

Returns:

210

bool, True if OpenID 1.x

211

"""

212

213

def isSigned(self, ns_uri, ns_key):

214

"""

215

Check if a specific field is signed in the response.

216

217

Parameters:

218

- ns_uri: str, namespace URI

219

- ns_key: str, field key

220

221

Returns:

222

bool, True if field is signed

223

"""

224

225

def getSigned(self, ns_uri, ns_key, default=None):

226

"""

227

Get a signed field value from the response.

228

229

Parameters:

230

- ns_uri: str, namespace URI

231

- ns_key: str, field key

232

- default: default value if field not found

233

234

Returns:

235

str or default, field value

236

"""

237

238

def getSignedNS(self, ns_uri):

239

"""

240

Get all signed fields in a namespace.

241

242

Parameters:

243

- ns_uri: str, namespace URI

244

245

Returns:

246

dict, signed fields in namespace

247

"""

248

249

def extensionResponse(self, namespace_uri, require_signed):

250

"""

251

Extract extension data from response.

252

253

Parameters:

254

- namespace_uri: str, extension namespace URI

255

- require_signed: bool, whether to require signed data

256

257

Returns:

258

dict, extension data

259

"""

260

261

def getReturnTo(self):

262

"""

263

Get the return_to URL from response.

264

265

Returns:

266

str, return_to URL

267

"""

268

269

class FailureResponse(Response):

270

"""Failed authentication response with status FAILURE."""

271

272

def __init__(self, endpoint, message=None, contact=None, reference=None):

273

"""

274

Initialize a failure response.

275

276

Parameters:

277

- endpoint: OpenIDServiceEndpoint or None

278

- message: str or None, failure reason message

279

- contact: str or None, contact information for support

280

- reference: str or None, reference identifier for this failure

281

"""

282

283

# Attributes:

284

# message: str or None - failure reason message

285

# contact: str or None - contact information for support

286

# reference: str or None - reference identifier for this failure

287

288

class CancelResponse(Response):

289

"""User-cancelled authentication response with status CANCEL."""

290

291

def __init__(self, endpoint):

292

"""

293

Initialize a cancel response.

294

295

Parameters:

296

- endpoint: OpenIDServiceEndpoint or None

297

"""

298

299

class SetupNeededResponse(Response):

300

"""Setup needed for immediate mode response with status SETUP_NEEDED."""

301

302

def __init__(self, endpoint, setup_url=None):

303

"""

304

Initialize a setup needed response.

305

306

Parameters:

307

- endpoint: OpenIDServiceEndpoint or None

308

- setup_url: str or None, URL for user setup (OpenID 1.x only)

309

"""

310

311

# Attributes:

312

# setup_url: str or None - URL that can be used to send the user to the

313

# server to set up for authentication. None in OpenID 2.0.

314

```

315

316

## Usage Examples

317

318

### Basic Consumer Implementation

319

320

```python

321

from openid.consumer import consumer

322

from openid.store.filestore import FileOpenIDStore

323

324

# Initialize consumer

325

store = FileOpenIDStore('/tmp/openid_store')

326

openid_consumer = consumer.Consumer({}, store)

327

328

# Start authentication

329

user_url = "https://example.com/user"

330

try:

331

auth_request = openid_consumer.begin(user_url)

332

redirect_url = auth_request.redirectURL(

333

realm="https://mysite.com",

334

return_to="https://mysite.com/openid/complete"

335

)

336

# Redirect user to redirect_url

337

except consumer.DiscoveryFailure as e:

338

print(f"Discovery failed: {e}")

339

```

340

341

### Complete Authentication Flow

342

343

```python

344

# Handle return from identity provider

345

def handle_openid_return(request):

346

query = dict(request.GET.items())

347

current_url = request.build_absolute_uri()

348

349

response = openid_consumer.complete(query, current_url)

350

351

if response.status == consumer.SUCCESS:

352

print(f"Success! Identity URL: {response.identity_url}")

353

print(f"Display identifier: {response.getDisplayIdentifier()}")

354

355

# Extract extension data if present

356

sreg_response = sreg.SRegResponse.fromSuccessResponse(response)

357

if sreg_response:

358

email = sreg_response.get('email')

359

nickname = sreg_response.get('nickname')

360

361

elif response.status == consumer.FAILURE:

362

print(f"Authentication failed: {response.message}")

363

elif response.status == consumer.CANCEL:

364

print("Authentication cancelled by user")

365

elif response.status == consumer.SETUP_NEEDED:

366

print(f"Setup needed at: {response.setup_url}")

367

```

368

369

### Using Extensions

370

371

```python

372

from openid.extensions import sreg

373

374

# Add SREG extension to request

375

auth_request = openid_consumer.begin(user_url)

376

sreg_request = sreg.SRegRequest(

377

required=['nickname', 'email'],

378

optional=['fullname'],

379

policy_url="https://mysite.com/privacy"

380

)

381

auth_request.addExtension(sreg_request)

382

383

redirect_url = auth_request.redirectURL(

384

realm="https://mysite.com",

385

return_to="https://mysite.com/openid/complete"

386

)

387

```

388

389

## Types

390

391

```python { .api }

392

# Response status constants

393

SUCCESS = 'success'

394

FAILURE = 'failure'

395

CANCEL = 'cancel'

396

SETUP_NEEDED = 'setup_needed'

397

398

# Exception types

399

class ProtocolError(ValueError):

400

"""

401

OpenID protocol violation exception.

402

403

Raised when a message violates the OpenID protocol specification.

404

This is caught internally and converted to FailureResponse objects.

405

"""

406

407

class DiscoveryFailure(Exception):

408

"""

409

Discovery process failed exception.

410

411

Raised when OpenID discovery fails for a given identifier URL.

412

This can happen due to network issues, invalid URLs, or missing

413

OpenID service information.

414

"""

415

416

class SetupNeededError(Exception):

417

"""

418

Setup needed in immediate mode exception.

419

420

Internally-used exception that indicates an immediate-mode request

421

was cancelled because user setup is required.

422

"""

423

424

def __init__(self, user_setup_url=None):

425

"""

426

Initialize setup needed error.

427

428

Parameters:

429

- user_setup_url: str or None, URL for user setup

430

"""

431

432

class TypeURIMismatch(ProtocolError):

433

"""

434

Type URI mismatch protocol error.

435

436

Raised when expected OpenID type URIs don't match discovered

437

service endpoint type URIs during verification.

438

"""

439

440

def __init__(self, expected, endpoint):

441

"""

442

Initialize type URI mismatch error.

443

444

Parameters:

445

- expected: str, expected type URI

446

- endpoint: OpenIDServiceEndpoint, discovered endpoint

447

"""

448

449

class ServerError(Exception):

450

"""

451

Server-side error in OpenID response.

452

453

Raised when the OpenID server returns a 400 response code

454

to a direct request, indicating a server-side error condition.

455

"""

456

457

def __init__(self, error_text, error_code, message):

458

"""

459

Initialize server error.

460

461

Parameters:

462

- error_text: str, error message text

463

- error_code: str or None, error code from server

464

- message: Message, full OpenID message containing error

465

"""

466

467

@classmethod

468

def fromMessage(cls, message):

469

"""

470

Generate ServerError from OpenID error message.

471

472

Parameters:

473

- message: Message, OpenID message containing error information

474

475

Returns:

476

ServerError instance

477

"""

478

```