| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- from typing import Optional
- from fastapi.openapi.models import APIKey, APIKeyIn
- from fastapi.security.base import SecurityBase
- from starlette.exceptions import HTTPException
- from starlette.requests import Request
- from starlette.status import HTTP_403_FORBIDDEN
- from typing_extensions import Annotated, Doc
- class APIKeyBase(SecurityBase):
- @staticmethod
- def check_api_key(api_key: Optional[str], auto_error: bool) -> Optional[str]:
- if not api_key:
- if auto_error:
- raise HTTPException(
- status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
- )
- return None
- return api_key
- class APIKeyQuery(APIKeyBase):
- """
- API key authentication using a query parameter.
- This defines the name of the query parameter that should be provided in the request
- with the API key and integrates that into the OpenAPI documentation. It extracts
- the key value sent in the query parameter automatically and provides it as the
- dependency result. But it doesn't define how to send that API key to the client.
- ## Usage
- Create an instance object and use that object as the dependency in `Depends()`.
- The dependency result will be a string containing the key value.
- ## Example
- ```python
- from fastapi import Depends, FastAPI
- from fastapi.security import APIKeyQuery
- app = FastAPI()
- query_scheme = APIKeyQuery(name="api_key")
- @app.get("/items/")
- async def read_items(api_key: str = Depends(query_scheme)):
- return {"api_key": api_key}
- ```
- """
- def __init__(
- self,
- *,
- name: Annotated[
- str,
- Doc("Query parameter name."),
- ],
- scheme_name: Annotated[
- Optional[str],
- Doc(
- """
- Security scheme name.
- It will be included in the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- description: Annotated[
- Optional[str],
- Doc(
- """
- Security scheme description.
- It will be included in the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- auto_error: Annotated[
- bool,
- Doc(
- """
- By default, if the query parameter is not provided, `APIKeyQuery` will
- automatically cancel the request and send the client an error.
- If `auto_error` is set to `False`, when the query parameter is not
- available, instead of erroring out, the dependency result will be
- `None`.
- This is useful when you want to have optional authentication.
- It is also useful when you want to have authentication that can be
- provided in one of multiple optional ways (for example, in a query
- parameter or in an HTTP Bearer token).
- """
- ),
- ] = True,
- ):
- self.model: APIKey = APIKey(
- **{"in": APIKeyIn.query}, # type: ignore[arg-type]
- name=name,
- description=description,
- )
- self.scheme_name = scheme_name or self.__class__.__name__
- self.auto_error = auto_error
- async def __call__(self, request: Request) -> Optional[str]:
- api_key = request.query_params.get(self.model.name)
- return self.check_api_key(api_key, self.auto_error)
- class APIKeyHeader(APIKeyBase):
- """
- API key authentication using a header.
- This defines the name of the header that should be provided in the request with
- the API key and integrates that into the OpenAPI documentation. It extracts
- the key value sent in the header automatically and provides it as the dependency
- result. But it doesn't define how to send that key to the client.
- ## Usage
- Create an instance object and use that object as the dependency in `Depends()`.
- The dependency result will be a string containing the key value.
- ## Example
- ```python
- from fastapi import Depends, FastAPI
- from fastapi.security import APIKeyHeader
- app = FastAPI()
- header_scheme = APIKeyHeader(name="x-key")
- @app.get("/items/")
- async def read_items(key: str = Depends(header_scheme)):
- return {"key": key}
- ```
- """
- def __init__(
- self,
- *,
- name: Annotated[str, Doc("Header name.")],
- scheme_name: Annotated[
- Optional[str],
- Doc(
- """
- Security scheme name.
- It will be included in the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- description: Annotated[
- Optional[str],
- Doc(
- """
- Security scheme description.
- It will be included in the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- auto_error: Annotated[
- bool,
- Doc(
- """
- By default, if the header is not provided, `APIKeyHeader` will
- automatically cancel the request and send the client an error.
- If `auto_error` is set to `False`, when the header is not available,
- instead of erroring out, the dependency result will be `None`.
- This is useful when you want to have optional authentication.
- It is also useful when you want to have authentication that can be
- provided in one of multiple optional ways (for example, in a header or
- in an HTTP Bearer token).
- """
- ),
- ] = True,
- ):
- self.model: APIKey = APIKey(
- **{"in": APIKeyIn.header}, # type: ignore[arg-type]
- name=name,
- description=description,
- )
- self.scheme_name = scheme_name or self.__class__.__name__
- self.auto_error = auto_error
- async def __call__(self, request: Request) -> Optional[str]:
- api_key = request.headers.get(self.model.name)
- return self.check_api_key(api_key, self.auto_error)
- class APIKeyCookie(APIKeyBase):
- """
- API key authentication using a cookie.
- This defines the name of the cookie that should be provided in the request with
- the API key and integrates that into the OpenAPI documentation. It extracts
- the key value sent in the cookie automatically and provides it as the dependency
- result. But it doesn't define how to set that cookie.
- ## Usage
- Create an instance object and use that object as the dependency in `Depends()`.
- The dependency result will be a string containing the key value.
- ## Example
- ```python
- from fastapi import Depends, FastAPI
- from fastapi.security import APIKeyCookie
- app = FastAPI()
- cookie_scheme = APIKeyCookie(name="session")
- @app.get("/items/")
- async def read_items(session: str = Depends(cookie_scheme)):
- return {"session": session}
- ```
- """
- def __init__(
- self,
- *,
- name: Annotated[str, Doc("Cookie name.")],
- scheme_name: Annotated[
- Optional[str],
- Doc(
- """
- Security scheme name.
- It will be included in the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- description: Annotated[
- Optional[str],
- Doc(
- """
- Security scheme description.
- It will be included in the generated OpenAPI (e.g. visible at `/docs`).
- """
- ),
- ] = None,
- auto_error: Annotated[
- bool,
- Doc(
- """
- By default, if the cookie is not provided, `APIKeyCookie` will
- automatically cancel the request and send the client an error.
- If `auto_error` is set to `False`, when the cookie is not available,
- instead of erroring out, the dependency result will be `None`.
- This is useful when you want to have optional authentication.
- It is also useful when you want to have authentication that can be
- provided in one of multiple optional ways (for example, in a cookie or
- in an HTTP Bearer token).
- """
- ),
- ] = True,
- ):
- self.model: APIKey = APIKey(
- **{"in": APIKeyIn.cookie}, # type: ignore[arg-type]
- name=name,
- description=description,
- )
- self.scheme_name = scheme_name or self.__class__.__name__
- self.auto_error = auto_error
- async def __call__(self, request: Request) -> Optional[str]:
- api_key = request.cookies.get(self.model.name)
- return self.check_api_key(api_key, self.auto_error)
|