Reference
armasec.armasec
This module defines the core Armasec class.
Armasec
This is a factory class for TokenSecurity. It allows the machinery of armasec to be initialized
correctly so that the factory method lockdown
can initialize new instances of TokenSecurity
to protect routes. It's not essential to use Armasec to secure routes, but it cuts down on the
boilerplate necessary to do so.
__init__
__init__(domain_configs: Optional[List[DomainConfig]] = None, debug_logger: Optional[Callable[[str], None]] = noop, debug_exceptions: bool = False, **kargs)
Stores initialization values for the TokenSecurity. All are passed through.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
domain_configs |
Optional[List[DomainConfig]]
|
List of domain configuration to authenticate the tokens against. |
None
|
debug_logger |
Optional[Callable[[str], None]]
|
A callable, that if provided, will allow debug logging. Should be
passed as a logger method like |
noop
|
debug_exceptions |
bool
|
If True, raise original exceptions. Should only be used in a testing or debugging context. |
False
|
kargs |
Arguments compatible to instantiate the DomainConfig model. |
{}
|
lockdown
cached
lockdown(*scopes: str, permission_mode: PermissionMode = PermissionMode.ALL, skip_plugins: bool = False) -> TokenSecurity
Initialize an instance of TokenSecurity to lockdown a route. Uses memoization to minimize the number of TokenSecurity instances initialized. Applies supplied permission_mode when checking token permssions against TokenSecurity scopes.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
scopes |
str
|
A list of scopes needed to access the endpoint. |
()
|
permissions_mode |
If "ALL", all scopes listed are required for access. If "SOME", only one of the scopes listed are required for access. |
required | |
skip_plugins |
bool
|
If True, do not evaluate plugin validators. |
False
|
lockdown_all
Initialize an instance of TokenSecurity to lockdown a route. Uses memoization to minimize
the number of TokenSecurity instances initialized. Requires all the scopes in the
TokenSecurity instance to be included in the token permissions. This is just a wrapper
around lockdown()
with default permission_mode and is only included for symmetry.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
scopes |
str
|
A list of the scopes needed to access the endpoint. All are required. |
()
|
skip_plugins |
bool
|
If True, do not evaluate plugin validators. |
False
|
lockdown_some
Initialize an instance of TokenSecurity to lockdown a route. Uses memoization to minimize the number of TokenSecurity instances initialized. Requires at least one permission in the token to match a scope attached to the TokenSecurity instance.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
scopes |
str
|
A list of the scopes needed to access the endpoint. Only one is required. |
()
|
skip_plugins |
bool
|
If True, do not evaluate plugin validators. |
False
|
armasec.exceptions
ArmasecError
Bases: Buzz
A custom exception class used for checking conditions and handling other exceptions.
Attributes:
Name | Type | Description |
---|---|---|
status_code |
int
|
The HTTP status code indicated by the error. Set to 400. |
AuthenticationError
Bases: ArmasecError
Indicates a failure to authenticate and decode jwt.
Attributes:
Name | Type | Description |
---|---|---|
status_code |
int
|
The HTTP status code indicated by the error. Set to 401. |
AuthorizationError
Bases: ArmasecError
Indicates that the provided claims don't match the claims required for a protected endpoint.
Attributes:
Name | Type | Description |
---|---|---|
status_code |
int
|
The HTTP status code indicated by the error. Set to 403. |
PayloadMappingError
Bases: ArmasecError
Indicates that the configured payload_claim_mapping did not match a path in the token.
Attributes:
Name | Type | Description |
---|---|---|
status_code |
int
|
The HTTP status code indicated by the error. Set to 500. |
armasec.openid_config_loader
This module provides the OpenidConfigLoader which is used to load openid-configuration data from an OIDC provider.
OpenidConfigLoader
config
property
Retrive the openid config from an OIDC provider. Lazy loads the config so that API calls are deferred until the coniguration is needed.
jwks
property
Retrives JWKs public keys from an OIDC provider. Lazy loads the jwks so that API calls are deferred until the jwks are needed.
__init__
Initializes a base TokenManager.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
secret |
The secret key needed to decode a token |
required | |
domain |
str
|
The domain of the OIDC provider. This is to construct the openid-configuration url |
required |
use_https |
bool
|
If falsey, use |
True
|
debug_logger |
Optional[Callable[..., None]]
|
A callable, that if provided, will allow debug logging. Should be passed
as a logger method like |
None
|
build_openid_config_url
staticmethod
Builds a url for an openid configuration given a domain.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
domain |
str
|
The domain of the OIDC provider for which to build a URL |
required |
use_https |
bool
|
Use |
True
|
armasec.pytest_extension
This module provides a pytest plugin for testing.
build_mock_openid_server
build_mock_openid_server(domain, openid_config, jwk, jwks_uri) -> Callable[[str, OpenidConfig, JWK, str], _GeneratorContextManager]
Provide a fixture that returns a context manager that mocks opend-config routes.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
domain |
The domain of the openid server to mock. |
required | |
openid_config |
The config to return from the mocked config route. |
required | |
jwk |
The jwk to return from the mocked jwk route. |
required | |
jwks_uri |
The URL of the jwks route to mock. |
required |
Returns:
Type | Description |
---|---|
Callable[[str, OpenidConfig, JWK, str], _GeneratorContextManager]
|
A context manager that, while active, mocks the openid routes needed by Armasec. |
build_rs256_token
Provide a fixture that returns a helper method that can build a JWT.
The JWT is signed with the private key provided by the rs256_private_key.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
rs256_private_key |
An implicit fixture parameter. |
required | |
rs256_iss |
An implicit fixture parameter. |
required | |
rs256_sub |
An implicit fixture parameter. |
required |
mock_openid_server
Provide a fixture that mocks an openid server using the extension fixtures.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
rs256_domain |
An implicit fixture parameter. |
required | |
rs256_openid_config |
An implicit fixture parameter. |
required | |
rs256_jwk |
An implicit fixture parameter. |
required | |
rs256_jwks_uri |
An implicit fixture parameter. |
required |
rs256_domain
Provide a fixture that returns a domain for use in other fixtures.
The value here doesn't really have anything to do with an actual domain name.
rs256_domain_config
Provide a fixture that returns the DomainConfig model for the default rs256 domain.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
rs256_domain |
An implicit fixture parameter. |
required |
rs256_iss
Provide a fixture that returns an issuer claim for use in other fixtures.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
rs256_domain |
An implicit fixture parameter. |
required |
rs256_jwk
Provide a fixture that returns a JWK for use in other fixtures.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
rs256_kid |
An implicit fixture parameter. |
required |
rs256_jwks_uri
Provide a fixture that returns a jwks uri for use in other fixtures.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
rs256_jwks_uri |
An implicit fixture parameter. |
required |
rs256_openid_config
Provide a fixture that returns an openid configuration for use in other fixtures.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
rs256_iss |
An implicit fixture parameter. |
required | |
rs256_jwks_uri |
An implicit fixture parameter. |
required |
rs256_private_key
Provide a fixture that returns a pre-generated private key for RS256 hashing in other fixtures.
rs256_public_key
Provide a fixture that returns a pre-generated public key for RS256 hashing in other fixtures.
armasec.token_decoder
This module provides an abstract base class for algorithmic token decoders
TokenDecoder
Decoder class used to decode tokens given an algorithm and jwks.
__init__
__init__(jwks: JWKs, algorithm: str = 'RS256', debug_logger: Callable[..., None] | None = None, decode_options_override: dict | None = None, permission_extractor: Callable[[dict], list[str]] | None = None)
Initializes a TokenDecoder.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
algorithm |
str
|
The algorithm to use for decoding. Defaults to RS256. |
'RS256'
|
jwks |
JWKs
|
JSON web keys object holding the public keys for decoding. |
required |
openid_config |
The openid_configuration needed for claims such as 'issuer'. |
required | |
debug_logger |
Callable[..., None] | None
|
A callable, that if provided, will allow debug logging. Should
be passed as a logger method like |
None
|
decode_options_override |
dict | None
|
Options that can override the default behavior of the jwt
decode method. For example, one can ignore token expiration by
setting this to |
None
|
permission_extractor |
Callable[[dict], list[str]] | None
|
Optional function that may be used to extract permissions from the decoded token dictionary when the permissions are not a top-level claim in the token. If not provided, permissions will be assumed to be a top-level claim in the token.
|
None
|
decode
Decode a JWT into a TokenPayload while checking signatures and claims.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
token |
str
|
The token to decode. |
required |
claims |
Additional claims to verify in the token. |
{}
|
get_decode_key
Search for a public keys within the JWKs that matches the incoming token.
Compares the token's unverified header against available JWKs. Uses the matching JWK for the decode key. Raise AuthenticationError if matching public key cannot be found.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
token |
str
|
The token to match against available JWKs. |
required |
extract_keycloak_permissions
Provide a permission extractor for Keycloak.
By default, Keycloak packages the roles for a given client nested within the "resource_access" claim. In order to extract those roles into the expected permissions in the TokenPayload, this permission_extractor can be used.
Here is an example decoded token from Keycloak (with some stuff removed to improve readability):
{
"exp": 1728627701,
"iat": 1728626801,
"jti": "24fdb7ef-d773-4e6b-982a-b8126dd58af7",
"sub": "dfa64115-40b5-46ab-924c-c376e73f631d",
"azp": "my-client",
"resource_access": {
"my-client": {
"roles": [
"read:stuff"
]
},
},
}
This extractor would extract the roles ["read:stuff"]
as the
permissions for the TokenPayload returned by the TokenDecoder.
armasec.token_manager
This module defines a TokenManager that can be used to extract token payloads from request headers.
TokenManager
Handle auth via a TokenDecoder and manage extraction from request headers and serialization into TokenPayload instances.
__init__
__init__(openid_config: OpenidConfig, token_decoder: TokenDecoder, audience: Optional[str] = None, debug_logger: Optional[Callable[..., None]] = None, decode_options_override: Optional[dict] = None)
Initialize a base TokenManager.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
openid_config |
OpenidConfig
|
The openid_configuration needed for claims such as 'issuer'. |
required |
token_decoder |
TokenDecoder
|
The decoder used to verify jwts |
required |
audience |
Optional[str]
|
An optional audience to check in decoded tokens. |
None
|
debug_logger |
Optional[Callable[..., None]]
|
A callable, that if provided, will allow debug logging. Should
be passed as a logger method like |
None
|
decode_options_override |
Optional[dict]
|
Options that can override the default behavior of the jwt
decode method. For example, one can ignore token expiration by
setting this to |
None
|
extract_token_payload
Retrieve a token from a request header and decode it into a TokenPayload.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
headers |
Union[Headers, dict]
|
The headers from which to retrieve a JWT. |
required |
armasec.token_payload
This module defines a pydantic schema for the payload of a jwt.
TokenPayload
Bases: BaseModel
A convenience class that can be used to access parts of a decoded jwt.
Attributes:
Name | Type | Description |
---|---|---|
sub |
str
|
The "sub" claim from a JWT. |
permissions |
List[str]
|
The permissions claims extracted from a JWT. |
expire |
Optional[datetime]
|
The "exp" claim extracted from a JWT. |
client_id |
Optional[str]
|
The "azp" claim extracted from a JWT. |
original_token |
Optional[str]
|
The original token value |
armasec.token_security
This module defines a TokenSecurity injectable that can be used enforce access on FastAPI routes.
ManagerConfig
Bases: BaseModel
Model class to represent a TokenManager instance and its domain configuration for easier mapping
Attributes:
Name | Type | Description |
---|---|---|
manager |
TokenManager
|
The TokenManager instance to use for decoding tokens. |
domain_config |
DomainConfig
|
The DomainConfig for the openid server. |
PermissionMode
Bases: AutoNameEnum
Endpoint permissions.
Attributes:
Name | Type | Description |
---|---|---|
ALL |
Require all listed permissions. |
|
SOME |
Require at least one of the listed permissions. |
TokenSecurity
Bases: APIKeyBase
An injectable Security class that returns a TokenPayload when used with Depends().
Attributes:
Name | Type | Description |
---|---|---|
manager |
Optional[TokenManager]
|
The TokenManager to use for token validation and extraction. |
__call__
async
This method is called by FastAPI's dependency injection system when a TokenSecurity instance is injected to a route endpoint via the Depends() method. Lazily loads the OIDC config, the TokenDecoder, and the TokenManager if they are not already initialized.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
request |
Request
|
The FastAPI request to check for secure access. |
required |
__init__
__init__(domain_configs: List[DomainConfig], scopes: Optional[Iterable[str]] = None, permission_mode: PermissionMode = PermissionMode.ALL, debug_logger: Optional[Callable[..., None]] = None, debug_exceptions: bool = False, skip_plugins: bool = False)
Initializes the TokenSecurity instance.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
domain_configs |
List[DomainConfig]
|
List of domain configuration to authenticate the tokens against. |
required |
scopes |
Optional[Iterable[str]]
|
Optional permissions scopes that should be checked |
None
|
permission_mode |
PermissionMode
|
The PermissionMode to apply in the protected route. |
ALL
|
debug_logger |
Optional[Callable[..., None]]
|
A callable, that if provided, will allow debug logging. Should be
passed as a logger method like |
None
|
debug_exceptions |
bool
|
If True, raise original exceptions. Should only be used in a testing or debugging context. |
False
|
skip_plugins |
bool
|
If True, do not evaluate plugin validators. |
False
|
armasec.utilities
Provides some utility functions.
log_error
Logs an en error with the supplied message, a string representation of the error, and its
traceback. If the logger supplied is noop, do nothing. Pass as a partial when using the Buzz
handle_errors
context manager::
with Buzz.handle_errors("Boom!", do_except=partial(log_error, debug_logger)):
do_some_risky_stuff()
armasec.schemas.armasec_config
This module provides a pydantic schema describing Armasec's configuration parameters.
DomainConfig
Bases: BaseModel
This model provides a specification for the input domains to authenticate against. It expects the domain indeed and the audience to refer to.
Attributes:
Name | Type | Description |
---|---|---|
domain |
str
|
The OIDC domain from which resources are loaded. |
audience |
Optional[str]
|
Optional designation of the token audience. |
algorithm |
str
|
The Algorithm to use for decoding. Defaults to RS256. |
use_https |
bool
|
If true, use |
match_keys |
Dict[str, Union[str, List[Any], Dict[Any, Any], Set[Any], bool, int, float]]
|
Dictionary of k/v pairs to match in the token when decoding it. |
armasec.schemas.jwks
This module provides pydantic schemas for JSON Web Keys.
JWK
Bases: BaseModel
This Model provides a specification for the objects retrieved from JWK endpoints in OIDC providers. It also assists with validation and item access.
Attributes:
Name | Type | Description |
---|---|---|
alg |
str
|
The algorithm to use for hash validation. |
e |
str
|
The exponent parameter to use in RS256 hashing |
kid |
str
|
The "kid" claim to uniquely identify the key. |
kty |
str
|
The "kty" claim to identify the type of the key. |
n |
str
|
The modulus parameter to use in RS256 hashing. |
use |
Optional[str]
|
The claim that identifies the intended use of the public key. |
x5c |
Optional[List[str]]
|
The X.509 certificate chain parameter |
x5c |
Optional[List[str]]
|
The X.509 certificate SHA-1 thumbprint parameter |
JWKs
Bases: BaseModel
This Model provides a specification for the container object retrieved from JWK endpoints in OIDC providers. It also assists with validation and item access.
Attributes:
Name | Type | Description |
---|---|---|
keys |
List[JWK]
|
The list of JWKs contained within. |
armasec.schemas.openid_config
This module provides a pydantic schema describing openid-configuration data.
OpenidConfig
Bases: BaseModel
Provides a specification for the objects retrieved from openid_configuration endpoint of the OIDC providers. Only includes needed fields for supported Manager instances. Assists with validation and item access.
Attributes:
Name | Type | Description |
---|---|---|
issuer |
AnyHttpUrl
|
The URL of the issuer of the tokens. |
jwks_uri |
AnyHttpUrl
|
The URI where JWKs can be foun don the OpenID server. |
armasec.pluggable
Manage plugins from armasec.
armasec.pluggable.hookspecs
Hook specification module for armasec plugins.
armasec_plugin_check
armasec_plugin_check(request: Request, token_payload: TokenPayload, debug_logger: Callable[..., None]) -> None
Check a token payload for validity against a request using your plugin.
If the check fails, it should raise a ArmasecError or a subclass thereof.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
request |
Request
|
The original request made to the secured endpoint. Will be passed to the plugin method if the implementation includes it as a keyword argument. |
required |
token_payload |
TokenPayload
|
The contents of the auth token. Will be passed ot the plugin method if the implementation includes it as a keyword argument |
required |
debug_logger |
Callable[..., None]
|
A callable, that if provided, will allow debug logging. Should be
passed as a logger method like |
required |