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

39 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2025-05-05 00:03 +0000

1from typing import Optional 1abcdef

2 

3from fastapi.openapi.models import APIKey, APIKeyIn 1abcdef

4from fastapi.security.base import SecurityBase 1abcdef

5from starlette.exceptions import HTTPException 1abcdef

6from starlette.requests import Request 1abcdef

7from starlette.status import HTTP_403_FORBIDDEN 1abcdef

8from typing_extensions import Annotated, Doc 1abcdef

9 

10 

11class APIKeyBase(SecurityBase): 1abcdef

12 @staticmethod 1abcdef

13 def check_api_key(api_key: Optional[str], auto_error: bool) -> Optional[str]: 1abcdef

14 if not api_key: 28 g 9 h ! i # j $ k % l ' m ( n ) o * p + q , r - s . t / u : v ; w = x ? y @ z [ A ] B ^ C _ D ` E { F | G } H ~ I abJ bbK cbL dbM ebN fbO gbP hbQ ibR jbS kbT lbU mbV nbW obX pbY qbZ rb0 sb1 tb2 ub3 vb4 wb5 xb6 yb7

15 if auto_error: 1ghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567

16 raise HTTPException( 1ghjkmnpqstvwyzBCEFHIKLNOQRTUWXZ02356

17 status_code=HTTP_403_FORBIDDEN, detail="Not authenticated" 

18 ) 

19 return None 1iloruxADGJMPSVY147

20 return api_key 28 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbyb

21 

22 

23class APIKeyQuery(APIKeyBase): 1abcdef

24 """ 

25 API key authentication using a query parameter. 

26 

27 This defines the name of the query parameter that should be provided in the request 

28 with the API key and integrates that into the OpenAPI documentation. It extracts 

29 the key value sent in the query parameter automatically and provides it as the 

30 dependency result. But it doesn't define how to send that API key to the client. 

31 

32 ## Usage 

33 

34 Create an instance object and use that object as the dependency in `Depends()`. 

35 

36 The dependency result will be a string containing the key value. 

37 

38 ## Example 

39 

40 ```python 

41 from fastapi import Depends, FastAPI 

42 from fastapi.security import APIKeyQuery 

43 

44 app = FastAPI() 

45 

46 query_scheme = APIKeyQuery(name="api_key") 

47 

48 

49 @app.get("/items/") 

50 async def read_items(api_key: str = Depends(query_scheme)): 

51 return {"api_key": api_key} 

52 ``` 

53 """ 

54 

55 def __init__( 1abcdef

56 self, 

57 *, 

58 name: Annotated[ 

59 str, 

60 Doc("Query parameter name."), 

61 ], 

62 scheme_name: Annotated[ 

63 Optional[str], 

64 Doc( 

65 """ 

66 Security scheme name. 

67 

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

69 """ 

70 ), 

71 ] = None, 

72 description: Annotated[ 

73 Optional[str], 

74 Doc( 

75 """ 

76 Security scheme description. 

77 

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

79 """ 

80 ), 

81 ] = None, 

82 auto_error: Annotated[ 

83 bool, 

84 Doc( 

85 """ 

86 By default, if the query parameter is not provided, `APIKeyQuery` will 

87 automatically cancel the request and send the client an error. 

88 

89 If `auto_error` is set to `False`, when the query parameter is not 

90 available, instead of erroring out, the dependency result will be 

91 `None`. 

92 

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

94 

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

96 provided in one of multiple optional ways (for example, in a query 

97 parameter or in an HTTP Bearer token). 

98 """ 

99 ), 

100 ] = True, 

101 ): 

102 self.model: APIKey = APIKey( 1abcdef

103 **{"in": APIKeyIn.query}, # type: ignore[arg-type] 

104 name=name, 

105 description=description, 

106 ) 

107 self.scheme_name = scheme_name or self.__class__.__name__ 1abcdef

108 self.auto_error = auto_error 1abcdef

109 

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

111 api_key = request.query_params.get(self.model.name) 2' m ( n ) o : v ; w = x ` E { F | G ebN fbO gbP nbW obX pbY wb5 xb6 yb7

112 return self.check_api_key(api_key, self.auto_error) 2' m ( n ) o : v ; w = x ` E { F | G ebN fbO gbP nbW obX pbY wb5 xb6 yb7

113 

114 

115class APIKeyHeader(APIKeyBase): 1abcdef

116 """ 

117 API key authentication using a header. 

118 

119 This defines the name of the header that should be provided in the request with 

120 the API key and integrates that into the OpenAPI documentation. It extracts 

121 the key value sent in the header automatically and provides it as the dependency 

122 result. But it doesn't define how to send that key to the client. 

123 

124 ## Usage 

125 

126 Create an instance object and use that object as the dependency in `Depends()`. 

127 

128 The dependency result will be a string containing the key value. 

129 

130 ## Example 

131 

132 ```python 

133 from fastapi import Depends, FastAPI 

134 from fastapi.security import APIKeyHeader 

135 

136 app = FastAPI() 

137 

138 header_scheme = APIKeyHeader(name="x-key") 

139 

140 

141 @app.get("/items/") 

142 async def read_items(key: str = Depends(header_scheme)): 

143 return {"key": key} 

144 ``` 

145 """ 

146 

147 def __init__( 1abcdef

148 self, 

149 *, 

150 name: Annotated[str, Doc("Header name.")], 

151 scheme_name: Annotated[ 

152 Optional[str], 

153 Doc( 

154 """ 

155 Security scheme name. 

156 

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

158 """ 

159 ), 

160 ] = None, 

161 description: Annotated[ 

162 Optional[str], 

163 Doc( 

164 """ 

165 Security scheme description. 

166 

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

168 """ 

169 ), 

170 ] = None, 

171 auto_error: Annotated[ 

172 bool, 

173 Doc( 

174 """ 

175 By default, if the header is not provided, `APIKeyHeader` will 

176 automatically cancel the request and send the client an error. 

177 

178 If `auto_error` is set to `False`, when the header is not available, 

179 instead of erroring out, the dependency result will be `None`. 

180 

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

182 

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

184 provided in one of multiple optional ways (for example, in a header or 

185 in an HTTP Bearer token). 

186 """ 

187 ), 

188 ] = True, 

189 ): 

190 self.model: APIKey = APIKey( 1abcdef

191 **{"in": APIKeyIn.header}, # type: ignore[arg-type] 

192 name=name, 

193 description=description, 

194 ) 

195 self.scheme_name = scheme_name or self.__class__.__name__ 1abcdef

196 self.auto_error = auto_error 1abcdef

197 

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

199 api_key = request.headers.get(self.model.name) 2# j $ k % l - s . t / u ] B ^ C _ D bbK cbL dbM kbT lbU mbV tb2 ub3 vb4

200 return self.check_api_key(api_key, self.auto_error) 2# j $ k % l - s . t / u ] B ^ C _ D bbK cbL dbM kbT lbU mbV tb2 ub3 vb4

201 

202 

203class APIKeyCookie(APIKeyBase): 1abcdef

204 """ 

205 API key authentication using a cookie. 

206 

207 This defines the name of the cookie that should be provided in the request with 

208 the API key and integrates that into the OpenAPI documentation. It extracts 

209 the key value sent in the cookie automatically and provides it as the dependency 

210 result. But it doesn't define how to set that cookie. 

211 

212 ## Usage 

213 

214 Create an instance object and use that object as the dependency in `Depends()`. 

215 

216 The dependency result will be a string containing the key value. 

217 

218 ## Example 

219 

220 ```python 

221 from fastapi import Depends, FastAPI 

222 from fastapi.security import APIKeyCookie 

223 

224 app = FastAPI() 

225 

226 cookie_scheme = APIKeyCookie(name="session") 

227 

228 

229 @app.get("/items/") 

230 async def read_items(session: str = Depends(cookie_scheme)): 

231 return {"session": session} 

232 ``` 

233 """ 

234 

235 def __init__( 1abcdef

236 self, 

237 *, 

238 name: Annotated[str, Doc("Cookie name.")], 

239 scheme_name: Annotated[ 

240 Optional[str], 

241 Doc( 

242 """ 

243 Security scheme name. 

244 

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

246 """ 

247 ), 

248 ] = None, 

249 description: Annotated[ 

250 Optional[str], 

251 Doc( 

252 """ 

253 Security scheme description. 

254 

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

256 """ 

257 ), 

258 ] = None, 

259 auto_error: Annotated[ 

260 bool, 

261 Doc( 

262 """ 

263 By default, if the cookie is not provided, `APIKeyCookie` will 

264 automatically cancel the request and send the client an error. 

265 

266 If `auto_error` is set to `False`, when the cookie is not available, 

267 instead of erroring out, the dependency result will be `None`. 

268 

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

270 

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

272 provided in one of multiple optional ways (for example, in a cookie or 

273 in an HTTP Bearer token). 

274 """ 

275 ), 

276 ] = True, 

277 ): 

278 self.model: APIKey = APIKey( 1abcdef

279 **{"in": APIKeyIn.cookie}, # type: ignore[arg-type] 

280 name=name, 

281 description=description, 

282 ) 

283 self.scheme_name = scheme_name or self.__class__.__name__ 1abcdef

284 self.auto_error = auto_error 1abcdef

285 

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

287 api_key = request.cookies.get(self.model.name) 28 g 9 h ! i * p + q , r ? y @ z [ A } H ~ I abJ hbQ ibR jbS qbZ rb0 sb1

288 return self.check_api_key(api_key, self.auto_error) 28 g 9 h ! i * p + q , r ? y @ z [ A } H ~ I abJ hbQ ibR jbS qbZ rb0 sb1