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

67 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2025-12-04 08:29 +0000

1from typing import Any, Dict, List, Optional, Union, cast 1abcdefg

2 

3from annotated_doc import Doc 1abcdefg

4from fastapi.exceptions import HTTPException 1abcdefg

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

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

7from fastapi.param_functions import Form 1abcdefg

8from fastapi.security.base import SecurityBase 1abcdefg

9from fastapi.security.utils import get_authorization_scheme_param 1abcdefg

10from starlette.requests import Request 1abcdefg

11from starlette.status import HTTP_401_UNAUTHORIZED 1abcdefg

12 

13# TODO: import from typing when deprecating Python 3.9 

14from typing_extensions import Annotated 1abcdefg

15 

16 

17class OAuth2PasswordRequestForm: 1abcdefg

18 """ 

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

20 for an OAuth2 password flow. 

21 

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

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

24 fields `username` and `password`. 

25 

26 All the initialization parameters are extracted from the request. 

27 

28 Read more about it in the 

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

30 

31 ## Example 

32 

33 ```python 

34 from typing import Annotated 

35 

36 from fastapi import Depends, FastAPI 

37 from fastapi.security import OAuth2PasswordRequestForm 

38 

39 app = FastAPI() 

40 

41 

42 @app.post("/login") 

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

44 data = {} 

45 data["scopes"] = [] 

46 for scope in form_data.scopes: 

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

48 if form_data.client_id: 

49 data["client_id"] = form_data.client_id 

50 if form_data.client_secret: 

51 data["client_secret"] = form_data.client_secret 

52 return data 

53 ``` 

54 

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

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

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

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

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

60 """ 

61 

62 def __init__( 1abcdefg

63 self, 

64 *, 

65 grant_type: Annotated[ 

66 Union[str, None], 

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

68 Doc( 

69 """ 

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

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

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

73 `OAuth2PasswordRequestFormStrict` dependency. 

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 ), 

86 ], 

87 password: Annotated[ 

88 str, 

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

90 Doc( 

91 """ 

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

93 `password`. 

94 """ 

95 ), 

96 ], 

97 scope: Annotated[ 

98 str, 

99 Form(), 

100 Doc( 

101 """ 

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

103 scope is also a string. 

104 

105 For example, a single string with: 

106 

107 ```python 

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

109 ```` 

110 

111 would represent the scopes: 

112 

113 * `items:read` 

114 * `items:write` 

115 * `users:read` 

116 * `profile` 

117 * `openid` 

118 """ 

119 ), 

120 ] = "", 

121 client_id: Annotated[ 

122 Union[str, None], 

123 Form(), 

124 Doc( 

125 """ 

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

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

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

129 """ 

130 ), 

131 ] = None, 

132 client_secret: Annotated[ 

133 Union[str, None], 

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

135 Doc( 

136 """ 

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

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

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

140 auth. 

141 """ 

142 ), 

143 ] = None, 

144 ): 

145 self.grant_type = grant_type 2Q R S # $ % ' ( ) h i j k l T U V * + , - . / m n o p q W X Y : ; = ? @ [ r s t u v Z 0 1 ] ^ _ ` { | w x y z A 2 3 4 } ~ abbbcbdbB C D E F 5 6 7 ebfbgbhbibjbG H I J K 8 9 ! kblbmbnbobpbL M N O P

146 self.username = username 2Q R S # $ % ' ( ) h i j k l T U V * + , - . / m n o p q W X Y : ; = ? @ [ r s t u v Z 0 1 ] ^ _ ` { | w x y z A 2 3 4 } ~ abbbcbdbB C D E F 5 6 7 ebfbgbhbibjbG H I J K 8 9 ! kblbmbnbobpbL M N O P

147 self.password = password 2Q R S # $ % ' ( ) h i j k l T U V * + , - . / m n o p q W X Y : ; = ? @ [ r s t u v Z 0 1 ] ^ _ ` { | w x y z A 2 3 4 } ~ abbbcbdbB C D E F 5 6 7 ebfbgbhbibjbG H I J K 8 9 ! kblbmbnbobpbL M N O P

148 self.scopes = scope.split() 2Q R S # $ % ' ( ) h i j k l T U V * + , - . / m n o p q W X Y : ; = ? @ [ r s t u v Z 0 1 ] ^ _ ` { | w x y z A 2 3 4 } ~ abbbcbdbB C D E F 5 6 7 ebfbgbhbibjbG H I J K 8 9 ! kblbmbnbobpbL M N O P

149 self.client_id = client_id 2Q R S # $ % ' ( ) h i j k l T U V * + , - . / m n o p q W X Y : ; = ? @ [ r s t u v Z 0 1 ] ^ _ ` { | w x y z A 2 3 4 } ~ abbbcbdbB C D E F 5 6 7 ebfbgbhbibjbG H I J K 8 9 ! kblbmbnbobpbL M N O P

150 self.client_secret = client_secret 2Q R S # $ % ' ( ) h i j k l T U V * + , - . / m n o p q W X Y : ; = ? @ [ r s t u v Z 0 1 ] ^ _ ` { | w x y z A 2 3 4 } ~ abbbcbdbB C D E F 5 6 7 ebfbgbhbibjbG H I J K 8 9 ! kblbmbnbobpbL M N O P

151 

152 

153class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm): 1abcdefg

154 """ 

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

156 for an OAuth2 password flow. 

157 

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

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

160 fields `username` and `password`. 

161 

162 All the initialization parameters are extracted from the request. 

163 

164 The only difference between `OAuth2PasswordRequestFormStrict` and 

165 `OAuth2PasswordRequestForm` is that `OAuth2PasswordRequestFormStrict` requires the 

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

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

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

169 

170 Read more about it in the 

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

172 

173 ## Example 

174 

175 ```python 

176 from typing import Annotated 

177 

178 from fastapi import Depends, FastAPI 

179 from fastapi.security import OAuth2PasswordRequestForm 

180 

181 app = FastAPI() 

182 

183 

184 @app.post("/login") 

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

186 data = {} 

187 data["scopes"] = [] 

188 for scope in form_data.scopes: 

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

190 if form_data.client_id: 

191 data["client_id"] = form_data.client_id 

192 if form_data.client_secret: 

193 data["client_secret"] = form_data.client_secret 

194 return data 

195 ``` 

196 

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

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

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

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

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

202 

203 

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

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

206 OAuth2PasswordRequestForm dependency class. 

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

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

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

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

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

212 using HTTP Basic auth, as: client_id:client_secret 

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

214 using HTTP Basic auth, as: client_id:client_secret 

215 """ 

216 

217 def __init__( 1abcdefg

218 self, 

219 grant_type: Annotated[ 

220 str, 

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

222 Doc( 

223 """ 

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

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

226 permissive, use instead the `OAuth2PasswordRequestForm` dependency 

227 class. 

228 """ 

229 ), 

230 ], 

231 username: Annotated[ 

232 str, 

233 Form(), 

234 Doc( 

235 """ 

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

237 `username`. 

238 """ 

239 ), 

240 ], 

241 password: Annotated[ 

242 str, 

243 Form(), 

244 Doc( 

245 """ 

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

247 `password`. 

248 """ 

249 ), 

250 ], 

251 scope: Annotated[ 

252 str, 

253 Form(), 

254 Doc( 

255 """ 

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

257 scope is also a string. 

258 

259 For example, a single string with: 

260 

261 ```python 

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

263 ```` 

264 

265 would represent the scopes: 

266 

267 * `items:read` 

268 * `items:write` 

269 * `users:read` 

270 * `profile` 

271 * `openid` 

272 """ 

273 ), 

274 ] = "", 

275 client_id: Annotated[ 

276 Union[str, None], 

277 Form(), 

278 Doc( 

279 """ 

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

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

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

283 """ 

284 ), 

285 ] = None, 

286 client_secret: Annotated[ 

287 Union[str, None], 

288 Form(), 

289 Doc( 

290 """ 

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

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

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

294 auth. 

295 """ 

296 ), 

297 ] = None, 

298 ): 

299 super().__init__( 1QRSTUVWXYZ0123456789!

300 grant_type=grant_type, 

301 username=username, 

302 password=password, 

303 scope=scope, 

304 client_id=client_id, 

305 client_secret=client_secret, 

306 ) 

307 

308 

309class OAuth2(SecurityBase): 1abcdefg

310 """ 

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

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

313 each OAuth2 flow. 

314 

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

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

317 

318 Read more about it in the 

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

320 """ 

321 

322 def __init__( 1abcdefg

323 self, 

324 *, 

325 flows: Annotated[ 

326 Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]], 

327 Doc( 

328 """ 

329 The dictionary of OAuth2 flows. 

330 """ 

331 ), 

332 ] = OAuthFlowsModel(), 

333 scheme_name: Annotated[ 

334 Optional[str], 

335 Doc( 

336 """ 

337 Security scheme name. 

338 

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

340 """ 

341 ), 

342 ] = None, 

343 description: Annotated[ 

344 Optional[str], 

345 Doc( 

346 """ 

347 Security scheme description. 

348 

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

350 """ 

351 ), 

352 ] = None, 

353 auto_error: Annotated[ 

354 bool, 

355 Doc( 

356 """ 

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

358 OAuth2 authentication, it will automatically cancel the request and 

359 send the client an error. 

360 

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

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

363 be `None`. 

364 

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

366 

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

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

369 or in a cookie). 

370 """ 

371 ), 

372 ] = True, 

373 ): 

374 self.model = OAuth2Model( 1abcdefg

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

376 ) 

377 self.scheme_name = scheme_name or self.__class__.__name__ 1abcdefg

378 self.auto_error = auto_error 1abcdefg

379 

380 def make_not_authenticated_error(self) -> HTTPException: 1abcdefg

381 """ 

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

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

384 

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

386 as it's not defined in the specification. 

387 

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

389 it's probably the most common one. 

390 

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

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

393 

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

395 """ 

396 return HTTPException( 21cqbrbsbtbubvbwbxbybzbAb2cBbCbDbEbFbGbHbIbJbKbLb3cMbNbObPbQbRbSbTbUbVbWb4cXbYbZb0b1b2b3b4b5b6b7b5c8b9b!b#b$b%b'b(b)b*b+b6c,b-b.b/b:b;b=b?b@b[b]b7c^b_b`b{b|b}b~bacbcccdc

397 status_code=HTTP_401_UNAUTHORIZED, 

398 detail="Not authenticated", 

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

400 ) 

401 

402 async def __call__(self, request: Request) -> Optional[str]: 1abcdefg

403 authorization = request.headers.get("Authorization") 2*d1c+d,d~c-d.dad/d:d2c;d=dbd?d@dcd[d]d3c^d_ddd`d{ded|d}d4c~daefdbecegddeee5cfegehdheieidjeke6clemejdneoekdpeqe7creseldteuemdve

404 if not authorization: 2*d1c+d,d~c-d.dad/d:d2c;d=dbd?d@dcd[d]d3c^d_ddd`d{ded|d}d4c~daefdbecegddeee5cfegehdheieidjeke6clemejdneoekdpeqe7creseldteuemdve

405 if self.auto_error: 21c~cad2cbdcd3cdded4cfdgd5chdid6cjdkd7cldmd

406 raise self.make_not_authenticated_error() 21c2c3c4c5c6c7c

407 else: 

408 return None 2~cadbdcdddedfdgdhdidjdkdldmd

409 return authorization 2*d+d,d-d.d/d:d;d=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekelemeneoepeqereseteueve

410 

411 

412class OAuth2PasswordBearer(OAuth2): 1abcdefg

413 """ 

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

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

416 

417 Read more about it in the 

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

419 """ 

420 

421 def __init__( 1abcdefg

422 self, 

423 tokenUrl: Annotated[ 

424 str, 

425 Doc( 

426 """ 

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

428 that has `OAuth2PasswordRequestForm` as a dependency. 

429 """ 

430 ), 

431 ], 

432 scheme_name: Annotated[ 

433 Optional[str], 

434 Doc( 

435 """ 

436 Security scheme name. 

437 

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

439 """ 

440 ), 

441 ] = None, 

442 scopes: Annotated[ 

443 Optional[Dict[str, str]], 

444 Doc( 

445 """ 

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

447 use this dependency. 

448 """ 

449 ), 

450 ] = None, 

451 description: Annotated[ 

452 Optional[str], 

453 Doc( 

454 """ 

455 Security scheme description. 

456 

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

458 """ 

459 ), 

460 ] = None, 

461 auto_error: Annotated[ 

462 bool, 

463 Doc( 

464 """ 

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

466 OAuth2 authentication, it will automatically cancel the request and 

467 send the client an error. 

468 

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

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

471 be `None`. 

472 

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

474 

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

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

477 or in a cookie). 

478 """ 

479 ), 

480 ] = True, 

481 refreshUrl: Annotated[ 

482 Optional[str], 

483 Doc( 

484 """ 

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

486 """ 

487 ), 

488 ] = None, 

489 ): 

490 if not scopes: 1abcdefg

491 scopes = {} 1abcdefg

492 flows = OAuthFlowsModel( 1abcdefg

493 password=cast( 

494 Any, 

495 { 

496 "tokenUrl": tokenUrl, 

497 "refreshUrl": refreshUrl, 

498 "scopes": scopes, 

499 }, 

500 ) 

501 ) 

502 super().__init__( 1abcdefg

503 flows=flows, 

504 scheme_name=scheme_name, 

505 description=description, 

506 auto_error=auto_error, 

507 ) 

508 

509 async def __call__(self, request: Request) -> Optional[str]: 1abcdefg

510 authorization = request.headers.get("Authorization") 2ecfcgc8c9cnd!c#codubvbpdqdrdwbxbsdhcybzbh i Abj k l icjckclcmcnc$c%ctd'c(cudFbGbvdwdxdHbIbydocJbKbm n Lbo p q pcqcrcsctcuc)c*czd+c,cAdQbRbBdCdDdSbTbEdvcUbVbr s Wbt u v wcxcyczcAcBc-c.cFd/c:cGd1b2bHdIdJd3b4bKdCc5b6bw x 7by z A DcEcFcGcHcIc;c=cLd?c@cMd$b%bNdOdPd'b(bQdJc)b*bB C +bD E F KcLcMcNcOcPc[c]cRd^c_cSd:b;bTdUdVd=b?bWdQc@b[bG H ]bI J K RcScTcUcVcWc`c{cXd|c}cYd|b}bZd0d1d~bac2dXcbcccL M dcN O P YcZc0c

511 scheme, param = get_authorization_scheme_param(authorization) 2ecfcgc8c9cnd!c#codubvbpdqdrdwbxbsdhcybzbh i Abj k l icjckclcmcnc$c%ctd'c(cudFbGbvdwdxdHbIbydocJbKbm n Lbo p q pcqcrcsctcuc)c*czd+c,cAdQbRbBdCdDdSbTbEdvcUbVbr s Wbt u v wcxcyczcAcBc-c.cFd/c:cGd1b2bHdIdJd3b4bKdCc5b6bw x 7by z A DcEcFcGcHcIc;c=cLd?c@cMd$b%bNdOdPd'b(bQdJc)b*bB C +bD E F KcLcMcNcOcPc[c]cRd^c_cSd:b;bTdUdVd=b?bWdQc@b[bG H ]bI J K RcScTcUcVcWc`c{cXd|c}cYd|b}bZd0d1d~bac2dXcbcccL M dcN O P YcZc0c

512 if not authorization or scheme.lower() != "bearer": 2ecfcgc8c9cnd!c#codubvbpdqdrdwbxbsdhcybzbh i Abj k l icjckclcmcnc$c%ctd'c(cudFbGbvdwdxdHbIbydocJbKbm n Lbo p q pcqcrcsctcuc)c*czd+c,cAdQbRbBdCdDdSbTbEdvcUbVbr s Wbt u v wcxcyczcAcBc-c.cFd/c:cGd1b2bHdIdJd3b4bKdCc5b6bw x 7by z A DcEcFcGcHcIc;c=cLd?c@cMd$b%bNdOdPd'b(bQdJc)b*bB C +bD E F KcLcMcNcOcPc[c]cRd^c_cSd:b;bTdUdVd=b?bWdQc@b[bG H ]bI J K RcScTcUcVcWc`c{cXd|c}cYd|b}bZd0d1d~bac2dXcbcccL M dcN O P YcZc0c

513 if self.auto_error: 28c9c!c#cubvbwbxbybzbAb$c%c'c(cFbGbHbIbJbKbLb)c*c+c,cQbRbSbTbUbVbWb-c.c/c:c1b2b3b4b5b6b7b;c=c?c@c$b%b'b(b)b*b+b[c]c^c_c:b;b=b?b@b[b]b`c{c|c}c|b}b~bacbcccdc

514 raise self.make_not_authenticated_error() 2ubvbwbxbybzbAbFbGbHbIbJbKbLbQbRbSbTbUbVbWb1b2b3b4b5b6b7b$b%b'b(b)b*b+b:b;b=b?b@b[b]b|b}b~bacbcccdc

515 else: 

516 return None 28c9c!c#c$c%c'c(c)c*c+c,c-c.c/c:c;c=c?c@c[c]c^c_c`c{c|c}c

517 return param 2ecfcgcndodpdqdrdsdhch i j k l icjckclcmcnctdudvdwdxdydocm n o p q pcqcrcsctcuczdAdBdCdDdEdvcr s t u v wcxcyczcAcBcFdGdHdIdJdKdCcw x y z A DcEcFcGcHcIcLdMdNdOdPdQdJcB C D E F KcLcMcNcOcPcRdSdTdUdVdWdQcG H I J K RcScTcUcVcWcXdYdZd0d1d2dXcL M N O P YcZc0c

518 

519 

520class OAuth2AuthorizationCodeBearer(OAuth2): 1abcdefg

521 """ 

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

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

524 """ 

525 

526 def __init__( 1abcdefg

527 self, 

528 authorizationUrl: str, 

529 tokenUrl: Annotated[ 

530 str, 

531 Doc( 

532 """ 

533 The URL to obtain the OAuth2 token. 

534 """ 

535 ), 

536 ], 

537 refreshUrl: Annotated[ 

538 Optional[str], 

539 Doc( 

540 """ 

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

542 """ 

543 ), 

544 ] = None, 

545 scheme_name: Annotated[ 

546 Optional[str], 

547 Doc( 

548 """ 

549 Security scheme name. 

550 

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

552 """ 

553 ), 

554 ] = None, 

555 scopes: Annotated[ 

556 Optional[Dict[str, str]], 

557 Doc( 

558 """ 

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

560 use this dependency. 

561 """ 

562 ), 

563 ] = None, 

564 description: Annotated[ 

565 Optional[str], 

566 Doc( 

567 """ 

568 Security scheme description. 

569 

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

571 """ 

572 ), 

573 ] = None, 

574 auto_error: Annotated[ 

575 bool, 

576 Doc( 

577 """ 

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

579 OAuth2 authentication, it will automatically cancel the request and 

580 send the client an error. 

581 

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

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

584 be `None`. 

585 

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

587 

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

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

590 or in a cookie). 

591 """ 

592 ), 

593 ] = True, 

594 ): 

595 if not scopes: 1abcdefg

596 scopes = {} 1abcdefg

597 flows = OAuthFlowsModel( 1abcdefg

598 authorizationCode=cast( 

599 Any, 

600 { 

601 "authorizationUrl": authorizationUrl, 

602 "tokenUrl": tokenUrl, 

603 "refreshUrl": refreshUrl, 

604 "scopes": scopes, 

605 }, 

606 ) 

607 ) 

608 super().__init__( 1abcdefg

609 flows=flows, 

610 scheme_name=scheme_name, 

611 description=description, 

612 auto_error=auto_error, 

613 ) 

614 

615 async def __call__(self, request: Request) -> Optional[str]: 1abcdefg

616 authorization = request.headers.get("Authorization") 2qbrb3dsbtb4dBbCb5dDbEb6dMbNb7dObPb8dXbYb9dZb0b!d8b9b#d!b#b$d,b-b%d.b/b'd^b_b(d`b{b)d

617 scheme, param = get_authorization_scheme_param(authorization) 2qbrb3dsbtb4dBbCb5dDbEb6dMbNb7dObPb8dXbYb9dZb0b!d8b9b#d!b#b$d,b-b%d.b/b'd^b_b(d`b{b)d

618 if not authorization or scheme.lower() != "bearer": 2qbrb3dsbtb4dBbCb5dDbEb6dMbNb7dObPb8dXbYb9dZb0b!d8b9b#d!b#b$d,b-b%d.b/b'd^b_b(d`b{b)d

619 if self.auto_error: 2qbrbsbtbBbCbDbEbMbNbObPbXbYbZb0b8b9b!b#b,b-b.b/b^b_b`b{b

620 raise self.make_not_authenticated_error() 2qbrbsbtbBbCbDbEbMbNbObPbXbYbZb0b8b9b!b#b,b-b.b/b^b_b`b{b

621 else: 

622 return None # pragma: nocover 

623 return param 23d4d5d6d7d8d9d!d#d$d%d'd(d)d

624 

625 

626class SecurityScopes: 1abcdefg

627 """ 

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

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

630 

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

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

633 all those dependencies in a single place. 

634 

635 Read more about it in the 

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

637 """ 

638 

639 def __init__( 1abcdefg

640 self, 

641 scopes: Annotated[ 

642 Optional[List[str]], 

643 Doc( 

644 """ 

645 This will be filled by FastAPI. 

646 """ 

647 ), 

648 ] = None, 

649 ): 

650 self.scopes: Annotated[ 2ecfcgcwexeyezeAehch i j k l icjckclcmcncBeCeDeEeFeocm n o p q pcqcrcsctcucGeHeIeJeKevcr s t u v wcxcyczcAcBcLeMeNeOePeCcw x y z A DcEcFcGcHcIcQeReSeTeUeJcB C D E F KcLcMcNcOcPcVeWeXeYeZeQcG H I J K RcScTcUcVcWc0e1e2e3e4eXcL M N O P YcZc0c

651 List[str], 

652 Doc( 

653 """ 

654 The list of all the scopes required by dependencies. 

655 """ 

656 ), 

657 ] = scopes or [] 

658 self.scope_str: Annotated[ 2ecfcgcwexeyezeAehch i j k l icjckclcmcncBeCeDeEeFeocm n o p q pcqcrcsctcucGeHeIeJeKevcr s t u v wcxcyczcAcBcLeMeNeOePeCcw x y z A DcEcFcGcHcIcQeReSeTeUeJcB C D E F KcLcMcNcOcPcVeWeXeYeZeQcG H I J K RcScTcUcVcWc0e1e2e3e4eXcL M N O P YcZc0c

659 str, 

660 Doc( 

661 """ 

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

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

664 """ 

665 ), 

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