Coverage for fastapi / security / oauth2.py: 100%

66 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-02-12 18:15 +0000

1from typing import Annotated, Any, cast 1abcd

2 

3from annotated_doc import Doc 1abcd

4from fastapi.exceptions import HTTPException 1abcd

5from fastapi.openapi.models import OAuth2 as OAuth2Model 1abcd

6from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel 1abcd

7from fastapi.param_functions import Form 1abcd

8from fastapi.security.base import SecurityBase 1abcd

9from fastapi.security.utils import get_authorization_scheme_param 1abcd

10from starlette.requests import Request 1abcd

11from starlette.status import HTTP_401_UNAUTHORIZED 1abcd

12 

13 

14class OAuth2PasswordRequestForm: 1abcd

15 """ 

16 This is a dependency class to collect the `username` and `password` as form data 

17 for an OAuth2 password flow. 

18 

19 The OAuth2 specification dictates that for a password flow the data should be 

20 collected using form data (instead of JSON) and that it should have the specific 

21 fields `username` and `password`. 

22 

23 All the initialization parameters are extracted from the request. 

24 

25 Read more about it in the 

26 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). 

27 

28 ## Example 

29 

30 ```python 

31 from typing import Annotated 

32 

33 from fastapi import Depends, FastAPI 

34 from fastapi.security import OAuth2PasswordRequestForm 

35 

36 app = FastAPI() 

37 

38 

39 @app.post("/login") 

40 def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]): 

41 data = {} 

42 data["scopes"] = [] 

43 for scope in form_data.scopes: 

44 data["scopes"].append(scope) 

45 if form_data.client_id: 

46 data["client_id"] = form_data.client_id 

47 if form_data.client_secret: 

48 data["client_secret"] = form_data.client_secret 

49 return data 

50 ``` 

51 

52 Note that for OAuth2 the scope `items:read` is a single scope in an opaque string. 

53 You could have custom internal logic to separate it by colon characters (`:`) or 

54 similar, and get the two parts `items` and `read`. Many applications do that to 

55 group and organize permissions, you could do it as well in your application, just 

56 know that that it is application specific, it's not part of the specification. 

57 """ 

58 

59 def __init__( 1abcd

60 self, 

61 *, 

62 grant_type: Annotated[ 

63 str | None, 

64 Form(pattern="^password$"), 

65 Doc( 

66 """ 

67 The OAuth2 spec says it is required and MUST be the fixed string 

68 "password". Nevertheless, this dependency class is permissive and 

69 allows not passing it. If you want to enforce it, use instead the 

70 `OAuth2PasswordRequestFormStrict` dependency. 

71 

72 Read more about it in the 

73 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). 

74 """ 

75 ), 

76 ] = None, 

77 username: Annotated[ 

78 str, 

79 Form(), 

80 Doc( 

81 """ 

82 `username` string. The OAuth2 spec requires the exact field name 

83 `username`. 

84 

85 Read more about it in the 

86 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). 

87 """ 

88 ), 

89 ], 

90 password: Annotated[ 

91 str, 

92 Form(json_schema_extra={"format": "password"}), 

93 Doc( 

94 """ 

95 `password` string. The OAuth2 spec requires the exact field name 

96 `password`. 

97 

98 Read more about it in the 

99 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). 

100 """ 

101 ), 

102 ], 

103 scope: Annotated[ 

104 str, 

105 Form(), 

106 Doc( 

107 """ 

108 A single string with actually several scopes separated by spaces. Each 

109 scope is also a string. 

110 

111 For example, a single string with: 

112 

113 ```python 

114 "items:read items:write users:read profile openid" 

115 ```` 

116 

117 would represent the scopes: 

118 

119 * `items:read` 

120 * `items:write` 

121 * `users:read` 

122 * `profile` 

123 * `openid` 

124 

125 Read more about it in the 

126 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). 

127 """ 

128 ), 

129 ] = "", 

130 client_id: Annotated[ 

131 str | None, 

132 Form(), 

133 Doc( 

134 """ 

135 If there's a `client_id`, it can be sent as part of the form fields. 

136 But the OAuth2 specification recommends sending the `client_id` and 

137 `client_secret` (if any) using HTTP Basic auth. 

138 """ 

139 ), 

140 ] = None, 

141 client_secret: Annotated[ 

142 str | None, 

143 Form(json_schema_extra={"format": "password"}), 

144 Doc( 

145 """ 

146 If there's a `client_password` (and a `client_id`), they can be sent 

147 as part of the form fields. But the OAuth2 specification recommends 

148 sending the `client_id` and `client_secret` (if any) using HTTP Basic 

149 auth. 

150 """ 

151 ), 

152 ] = None, 

153 ): 

154 self.grant_type = grant_type 1CDELMNOPQtuvRSTefghiFGHUVWXYZwxy012jklmnIJK345678zAB9!#opqrs

155 self.username = username 1CDELMNOPQtuvRSTefghiFGHUVWXYZwxy012jklmnIJK345678zAB9!#opqrs

156 self.password = password 1CDELMNOPQtuvRSTefghiFGHUVWXYZwxy012jklmnIJK345678zAB9!#opqrs

157 self.scopes = scope.split() 1CDELMNOPQtuvRSTefghiFGHUVWXYZwxy012jklmnIJK345678zAB9!#opqrs

158 self.client_id = client_id 1CDELMNOPQtuvRSTefghiFGHUVWXYZwxy012jklmnIJK345678zAB9!#opqrs

159 self.client_secret = client_secret 1CDELMNOPQtuvRSTefghiFGHUVWXYZwxy012jklmnIJK345678zAB9!#opqrs

160 

161 

162class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm): 1abcd

163 """ 

164 This is a dependency class to collect the `username` and `password` as form data 

165 for an OAuth2 password flow. 

166 

167 The OAuth2 specification dictates that for a password flow the data should be 

168 collected using form data (instead of JSON) and that it should have the specific 

169 fields `username` and `password`. 

170 

171 All the initialization parameters are extracted from the request. 

172 

173 The only difference between `OAuth2PasswordRequestFormStrict` and 

174 `OAuth2PasswordRequestForm` is that `OAuth2PasswordRequestFormStrict` requires the 

175 client to send the form field `grant_type` with the value `"password"`, which 

176 is required in the OAuth2 specification (it seems that for no particular reason), 

177 while for `OAuth2PasswordRequestForm` `grant_type` is optional. 

178 

179 Read more about it in the 

180 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). 

181 

182 ## Example 

183 

184 ```python 

185 from typing import Annotated 

186 

187 from fastapi import Depends, FastAPI 

188 from fastapi.security import OAuth2PasswordRequestForm 

189 

190 app = FastAPI() 

191 

192 

193 @app.post("/login") 

194 def login(form_data: Annotated[OAuth2PasswordRequestFormStrict, Depends()]): 

195 data = {} 

196 data["scopes"] = [] 

197 for scope in form_data.scopes: 

198 data["scopes"].append(scope) 

199 if form_data.client_id: 

200 data["client_id"] = form_data.client_id 

201 if form_data.client_secret: 

202 data["client_secret"] = form_data.client_secret 

203 return data 

204 ``` 

205 

206 Note that for OAuth2 the scope `items:read` is a single scope in an opaque string. 

207 You could have custom internal logic to separate it by colon characters (`:`) or 

208 similar, and get the two parts `items` and `read`. Many applications do that to 

209 group and organize permissions, you could do it as well in your application, just 

210 know that that it is application specific, it's not part of the specification. 

211 

212 

213 grant_type: the OAuth2 spec says it is required and MUST be the fixed string "password". 

214 This dependency is strict about it. If you want to be permissive, use instead the 

215 OAuth2PasswordRequestForm dependency class. 

216 username: username string. The OAuth2 spec requires the exact field name "username". 

217 password: password string. The OAuth2 spec requires the exact field name "password". 

218 scope: Optional string. Several scopes (each one a string) separated by spaces. E.g. 

219 "items:read items:write users:read profile openid" 

220 client_id: optional string. OAuth2 recommends sending the client_id and client_secret (if any) 

221 using HTTP Basic auth, as: client_id:client_secret 

222 client_secret: optional string. OAuth2 recommends sending the client_id and client_secret (if any) 

223 using HTTP Basic auth, as: client_id:client_secret 

224 """ 

225 

226 def __init__( 1abcd

227 self, 

228 grant_type: Annotated[ 

229 str, 

230 Form(pattern="^password$"), 

231 Doc( 

232 """ 

233 The OAuth2 spec says it is required and MUST be the fixed string 

234 "password". This dependency is strict about it. If you want to be 

235 permissive, use instead the `OAuth2PasswordRequestForm` dependency 

236 class. 

237 

238 Read more about it in the 

239 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). 

240 """ 

241 ), 

242 ], 

243 username: Annotated[ 

244 str, 

245 Form(), 

246 Doc( 

247 """ 

248 `username` string. The OAuth2 spec requires the exact field name 

249 `username`. 

250 

251 Read more about it in the 

252 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). 

253 """ 

254 ), 

255 ], 

256 password: Annotated[ 

257 str, 

258 Form(), 

259 Doc( 

260 """ 

261 `password` string. The OAuth2 spec requires the exact field name 

262 `password`. 

263 

264 Read more about it in the 

265 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). 

266 """ 

267 ), 

268 ], 

269 scope: Annotated[ 

270 str, 

271 Form(), 

272 Doc( 

273 """ 

274 A single string with actually several scopes separated by spaces. Each 

275 scope is also a string. 

276 

277 For example, a single string with: 

278 

279 ```python 

280 "items:read items:write users:read profile openid" 

281 ```` 

282 

283 would represent the scopes: 

284 

285 * `items:read` 

286 * `items:write` 

287 * `users:read` 

288 * `profile` 

289 * `openid` 

290 

291 Read more about it in the 

292 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). 

293 """ 

294 ), 

295 ] = "", 

296 client_id: Annotated[ 

297 str | None, 

298 Form(), 

299 Doc( 

300 """ 

301 If there's a `client_id`, it can be sent as part of the form fields. 

302 But the OAuth2 specification recommends sending the `client_id` and 

303 `client_secret` (if any) using HTTP Basic auth. 

304 """ 

305 ), 

306 ] = None, 

307 client_secret: Annotated[ 

308 str | None, 

309 Form(), 

310 Doc( 

311 """ 

312 If there's a `client_password` (and a `client_id`), they can be sent 

313 as part of the form fields. But the OAuth2 specification recommends 

314 sending the `client_id` and `client_secret` (if any) using HTTP Basic 

315 auth. 

316 """ 

317 ), 

318 ] = None, 

319 ): 

320 super().__init__( 1CDEFGHIJK

321 grant_type=grant_type, 

322 username=username, 

323 password=password, 

324 scope=scope, 

325 client_id=client_id, 

326 client_secret=client_secret, 

327 ) 

328 

329 

330class OAuth2(SecurityBase): 1abcd

331 """ 

332 This is the base class for OAuth2 authentication, an instance of it would be used 

333 as a dependency. All other OAuth2 classes inherit from it and customize it for 

334 each OAuth2 flow. 

335 

336 You normally would not create a new class inheriting from it but use one of the 

337 existing subclasses, and maybe compose them if you want to support multiple flows. 

338 

339 Read more about it in the 

340 [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/). 

341 """ 

342 

343 def __init__( 1abcd

344 self, 

345 *, 

346 flows: Annotated[ 

347 OAuthFlowsModel | dict[str, dict[str, Any]], 

348 Doc( 

349 """ 

350 The dictionary of OAuth2 flows. 

351 """ 

352 ), 

353 ] = OAuthFlowsModel(), 

354 scheme_name: Annotated[ 

355 str | None, 

356 Doc( 

357 """ 

358 Security scheme name. 

359 

360 It will be included in the generated OpenAPI (e.g. visible at `/docs`). 

361 """ 

362 ), 

363 ] = None, 

364 description: Annotated[ 

365 str | None, 

366 Doc( 

367 """ 

368 Security scheme description. 

369 

370 It will be included in the generated OpenAPI (e.g. visible at `/docs`). 

371 """ 

372 ), 

373 ] = None, 

374 auto_error: Annotated[ 

375 bool, 

376 Doc( 

377 """ 

378 By default, if no HTTP Authorization header is provided, required for 

379 OAuth2 authentication, it will automatically cancel the request and 

380 send the client an error. 

381 

382 If `auto_error` is set to `False`, when the HTTP Authorization header 

383 is not available, instead of erroring out, the dependency result will 

384 be `None`. 

385 

386 This is useful when you want to have optional authentication. 

387 

388 It is also useful when you want to have authentication that can be 

389 provided in one of multiple optional ways (for example, with OAuth2 

390 or in a cookie). 

391 """ 

392 ), 

393 ] = True, 

394 ): 

395 self.model = OAuth2Model( 1abcd

396 flows=cast(OAuthFlowsModel, flows), description=description 

397 ) 

398 self.scheme_name = scheme_name or self.__class__.__name__ 1abcd

399 self.auto_error = auto_error 1abcd

400 

401 def make_not_authenticated_error(self) -> HTTPException: 1abcd

402 """ 

403 The OAuth 2 specification doesn't define the challenge that should be used, 

404 because a `Bearer` token is not really the only option to authenticate. 

405 

406 But declaring any other authentication challenge would be application-specific 

407 as it's not defined in the specification. 

408 

409 For practical reasons, this method uses the `Bearer` challenge by default, as 

410 it's probably the most common one. 

411 

412 If you are implementing an OAuth2 authentication scheme other than the provided 

413 ones in FastAPI (based on bearer tokens), you might want to override this. 

414 

415 Ref: https://datatracker.ietf.org/doc/html/rfc6749 

416 """ 

417 return HTTPException( 2Mb$ % ' ( ) * + , - . / : ; = Nb? @ [ ] ^ _ ` { | } ~ abbbcbObdbebfbgbhbibjbkblbmbnbobpbqb

418 status_code=HTTP_401_UNAUTHORIZED, 

419 detail="Not authenticated", 

420 headers={"WWW-Authenticate": "Bearer"}, 

421 ) 

422 

423 async def __call__(self, request: Request) -> str | None: 1abcd

424 authorization = request.headers.get("Authorization") 2EcMbFcGc1bHcIc2bJcKcNbLcMc3bNcOc4bPcQcObRcSc5bTcUc6bVc

425 if not authorization: 2EcMbFcGc1bHcIc2bJcKcNbLcMc3bNcOc4bPcQcObRcSc5bTcUc6bVc

426 if self.auto_error: 2Mb1b2bNb3b4bOb5b6b

427 raise self.make_not_authenticated_error() 2MbNbOb

428 else: 

429 return None 21b2b3b4b5b6b

430 return authorization 2EcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVc

431 

432 

433class OAuth2PasswordBearer(OAuth2): 1abcd

434 """ 

435 OAuth2 flow for authentication using a bearer token obtained with a password. 

436 An instance of it would be used as a dependency. 

437 

438 Read more about it in the 

439 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). 

440 """ 

441 

442 def __init__( 1abcd

443 self, 

444 tokenUrl: Annotated[ 

445 str, 

446 Doc( 

447 """ 

448 The URL to obtain the OAuth2 token. This would be the *path operation* 

449 that has `OAuth2PasswordRequestForm` as a dependency. 

450 

451 Read more about it in the 

452 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). 

453 """ 

454 ), 

455 ], 

456 scheme_name: Annotated[ 

457 str | None, 

458 Doc( 

459 """ 

460 Security scheme name. 

461 

462 It will be included in the generated OpenAPI (e.g. visible at `/docs`). 

463 """ 

464 ), 

465 ] = None, 

466 scopes: Annotated[ 

467 dict[str, str] | None, 

468 Doc( 

469 """ 

470 The OAuth2 scopes that would be required by the *path operations* that 

471 use this dependency. 

472 

473 Read more about it in the 

474 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). 

475 """ 

476 ), 

477 ] = None, 

478 description: Annotated[ 

479 str | None, 

480 Doc( 

481 """ 

482 Security scheme description. 

483 

484 It will be included in the generated OpenAPI (e.g. visible at `/docs`). 

485 """ 

486 ), 

487 ] = None, 

488 auto_error: Annotated[ 

489 bool, 

490 Doc( 

491 """ 

492 By default, if no HTTP Authorization header is provided, required for 

493 OAuth2 authentication, it will automatically cancel the request and 

494 send the client an error. 

495 

496 If `auto_error` is set to `False`, when the HTTP Authorization header 

497 is not available, instead of erroring out, the dependency result will 

498 be `None`. 

499 

500 This is useful when you want to have optional authentication. 

501 

502 It is also useful when you want to have authentication that can be 

503 provided in one of multiple optional ways (for example, with OAuth2 

504 or in a cookie). 

505 """ 

506 ), 

507 ] = True, 

508 refreshUrl: Annotated[ 

509 str | None, 

510 Doc( 

511 """ 

512 The URL to refresh the token and obtain a new one. 

513 """ 

514 ), 

515 ] = None, 

516 ): 

517 if not scopes: 1abcd

518 scopes = {} 1abcd

519 flows = OAuthFlowsModel( 1abcd

520 password=cast( 

521 Any, 

522 { 

523 "tokenUrl": tokenUrl, 

524 "refreshUrl": refreshUrl, 

525 "scopes": scopes, 

526 }, 

527 ) 

528 ) 

529 super().__init__( 1abcd

530 flows=flows, 

531 scheme_name=scheme_name, 

532 description=description, 

533 auto_error=auto_error, 

534 ) 

535 

536 async def __call__(self, request: Request) -> str | None: 1abcd

537 authorization = request.headers.get("Authorization") 2rbsbtbPbQb7bRbSb8b) * 9b+ !b#b$b, - %b'b. / t u v (b)b*bub: ; e f = g h i vbwbxbybzbAbTbUb+bVbWb,b^ _ -b` .b/b:b{ | ;b=b} ~ w x y ?b@b[bBbabbbj k cbl m n CbDbEbFbGbHbXbYb]bZb0b^bhbib_bjb`b{b|bkblb}b~bmbnbz A B acbcccIbobpbo p qbq r s JbKbLb

538 scheme, param = get_authorization_scheme_param(authorization) 2rbsbtbPbQb7bRbSb8b) * 9b+ !b#b$b, - %b'b. / t u v (b)b*bub: ; e f = g h i vbwbxbybzbAbTbUb+bVbWb,b^ _ -b` .b/b:b{ | ;b=b} ~ w x y ?b@b[bBbabbbj k cbl m n CbDbEbFbGbHbXbYb]bZb0b^bhbib_bjb`b{b|bkblb}b~bmbnbz A B acbcccIbobpbo p qbq r s JbKbLb

539 if not authorization or scheme.lower() != "bearer": 2rbsbtbPbQb7bRbSb8b) * 9b+ !b#b$b, - %b'b. / t u v (b)b*bub: ; e f = g h i vbwbxbybzbAbTbUb+bVbWb,b^ _ -b` .b/b:b{ | ;b=b} ~ w x y ?b@b[bBbabbbj k cbl m n CbDbEbFbGbHbXbYb]bZb0b^bhbib_bjb`b{b|bkblb}b~bmbnbz A B acbcccIbobpbo p qbq r s JbKbLb

540 if self.auto_error: 2PbQbRbSb) * + , - . / : ; = TbUbVbWb^ _ ` { | } ~ abbbcbXbYbZb0bhbibjbkblbmbnbobpbqb

541 raise self.make_not_authenticated_error() 2) * + , - . / : ; = ^ _ ` { | } ~ abbbcbhbibjbkblbmbnbobpbqb

542 else: 

543 return None 2PbQbRbSbTbUbVbWbXbYbZb0b

544 return param 2rbsbtb7b8b9b!b#b$b%b'bt u v (b)b*bube f g h i vbwbxbybzbAb+b,b-b.b/b:b;b=bw x y ?b@b[bBbj k l m n CbDbEbFbGbHb]b^b_b`b{b|b}b~bz A B acbcccIbo p q r s JbKbLb

545 

546 

547class OAuth2AuthorizationCodeBearer(OAuth2): 1abcd

548 """ 

549 OAuth2 flow for authentication using a bearer token obtained with an OAuth2 code 

550 flow. An instance of it would be used as a dependency. 

551 """ 

552 

553 def __init__( 1abcd

554 self, 

555 authorizationUrl: str, 

556 tokenUrl: Annotated[ 

557 str, 

558 Doc( 

559 """ 

560 The URL to obtain the OAuth2 token. 

561 """ 

562 ), 

563 ], 

564 refreshUrl: Annotated[ 

565 str | None, 

566 Doc( 

567 """ 

568 The URL to refresh the token and obtain a new one. 

569 """ 

570 ), 

571 ] = None, 

572 scheme_name: Annotated[ 

573 str | None, 

574 Doc( 

575 """ 

576 Security scheme name. 

577 

578 It will be included in the generated OpenAPI (e.g. visible at `/docs`). 

579 """ 

580 ), 

581 ] = None, 

582 scopes: Annotated[ 

583 dict[str, str] | None, 

584 Doc( 

585 """ 

586 The OAuth2 scopes that would be required by the *path operations* that 

587 use this dependency. 

588 """ 

589 ), 

590 ] = None, 

591 description: Annotated[ 

592 str | None, 

593 Doc( 

594 """ 

595 Security scheme description. 

596 

597 It will be included in the generated OpenAPI (e.g. visible at `/docs`). 

598 """ 

599 ), 

600 ] = None, 

601 auto_error: Annotated[ 

602 bool, 

603 Doc( 

604 """ 

605 By default, if no HTTP Authorization header is provided, required for 

606 OAuth2 authentication, it will automatically cancel the request and 

607 send the client an error. 

608 

609 If `auto_error` is set to `False`, when the HTTP Authorization header 

610 is not available, instead of erroring out, the dependency result will 

611 be `None`. 

612 

613 This is useful when you want to have optional authentication. 

614 

615 It is also useful when you want to have authentication that can be 

616 provided in one of multiple optional ways (for example, with OAuth2 

617 or in a cookie). 

618 """ 

619 ), 

620 ] = True, 

621 ): 

622 if not scopes: 1abcd

623 scopes = {} 1abcd

624 flows = OAuthFlowsModel( 1abcd

625 authorizationCode=cast( 

626 Any, 

627 { 

628 "authorizationUrl": authorizationUrl, 

629 "tokenUrl": tokenUrl, 

630 "refreshUrl": refreshUrl, 

631 "scopes": scopes, 

632 }, 

633 ) 

634 ) 

635 super().__init__( 1abcd

636 flows=flows, 

637 scheme_name=scheme_name, 

638 description=description, 

639 auto_error=auto_error, 

640 ) 

641 

642 async def __call__(self, request: Request) -> str | None: 1abcd

643 authorization = request.headers.get("Authorization") 2$ % dcec' ( fcgchcicjckclc? @ mcnc[ ] ocpcqcrcsctcucdbebvcwcfbgbxcyczcAcBcCcDc

644 scheme, param = get_authorization_scheme_param(authorization) 2$ % dcec' ( fcgchcicjckclc? @ mcnc[ ] ocpcqcrcsctcucdbebvcwcfbgbxcyczcAcBcCcDc

645 if not authorization or scheme.lower() != "bearer": 2$ % dcec' ( fcgchcicjckclc? @ mcnc[ ] ocpcqcrcsctcucdbebvcwcfbgbxcyczcAcBcCcDc

646 if self.auto_error: 2$ % ' ( ? @ [ ] dbebfbgb

647 raise self.make_not_authenticated_error() 2$ % ' ( ? @ [ ] dbebfbgb

648 else: 

649 return None # pragma: nocover 

650 return param 2dcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDc

651 

652 

653class SecurityScopes: 1abcd

654 """ 

655 This is a special class that you can define in a parameter in a dependency to 

656 obtain the OAuth2 scopes required by all the dependencies in the same chain. 

657 

658 This way, multiple dependencies can have different scopes, even when used in the 

659 same *path operation*. And with this, you can access all the scopes required in 

660 all those dependencies in a single place. 

661 

662 Read more about it in the 

663 [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/). 

664 """ 

665 

666 def __init__( 1abcd

667 self, 

668 scopes: Annotated[ 

669 list[str] | None, 

670 Doc( 

671 """ 

672 This will be filled by FastAPI. 

673 """ 

674 ), 

675 ] = None, 

676 ): 

677 self.scopes: Annotated[ 2rbsbtbWcXcYcZc0cube f g h i vbwbxbybzbAb1c2c3c4c5cBbj k l m n CbDbEbFbGbHb6c7c8c9c!cIbo p q r s JbKbLb

678 list[str], 

679 Doc( 

680 """ 

681 The list of all the scopes required by dependencies. 

682 """ 

683 ), 

684 ] = scopes or [] 

685 self.scope_str: Annotated[ 2rbsbtbWcXcYcZc0cube f g h i vbwbxbybzbAb1c2c3c4c5cBbj k l m n CbDbEbFbGbHb6c7c8c9c!cIbo p q r s JbKbLb

686 str, 

687 Doc( 

688 """ 

689 All the scopes required by all the dependencies in a single string 

690 separated by spaces, as defined in the OAuth2 specification. 

691 """ 

692 ), 

693 ] = " ".join(self.scopes)