Skip to main content

Authentikate

codecov PyPI version Maintenance Maintainer PyPI pyversions PyPI status PyPI download month Code style: black Checked with mypy Ruff

What is Authentikate?

Authentikate is a library that provides a simple interface to validate tokens and retrieve corresponding user information inside a django application.

Note: This library is still somewhat tied to the Arkitekt Framework. We are working on making it more generic. If you have any ideas, please open an issue or a PR.

Alternatives

There are a few alternatives to this library, but none of them provide the same functionality. The most popular alternative is Simple JWT or Strawberry-django Auth . Both of these libraries provide a great way to authenticate users. So you should seriously consider using them instead of this library.

Why Authentikate?

Authentikate was designed to work with the Arkitekt Framework and therefore comes with a few additional features that are not available in other libraries.

Features:

  • Designed to work with the more specific Oauth2 Self-Encoded Access Tokens
  • Models Oauth2 Clients and Scopes
  • Build in support for Guardian for object level permissions
  • Build in support for Static Tokens (Token that are hard coded into the settings, e.g. for testing)
  • Build in support for Strawberry
  • Designed to work with Koherent for audit logging
  • Imitation support with Imitation Tokens (Token that are hard coded into the settings, e.g. for testing)

Composed Usage

If you plan to use Authentikate with the Arkitekt Framework, you should consider the Kante library. It composes Authentikate with Koherent and provides a simple interface to authenticate and log all changes that are done by a specific app and user.

How do I use it?

Authentikate is a Django Libary, so you will have to add it to your INSTALLED_APPS in your settings.py file.

INSTALLED_APPS = [
    ...
    'guardian', # This is required for object level permissions
    'authentikate',
    ...
]

AUTHENTICATION_BACKENDS = [
    "django.contrib.auth.backends.ModelBackend",
    "guardian.backends.ObjectPermissionBackend", # This is required for object level permissions
]

You will also need some additional configuration in your `settings.py` file.

```python
AUTH_USER_MODEL = "authentikate.User"


AUTHENTIKATE = {
    "ISSUERS": [
        {
            "kind": "jwks_uri",
            "iss": "https://lok.my-org.com",
            "jwks_uri": "https://lok.my-org.com/.well-known/jwks.json",
            # Optional: refuse tokens lok has revoked before they expire. The
            # list is fetched at most once a minute (configurable), not per request.
            "revocation_uri": "https://lok.my-org.com/o/revoked/",
        }
    ],
    # This service's identifier, checked against the token's `aud`. Required —
    # without it a token your issuer minted for any other service would be
    # accepted here. Use "*" to accept any audience deliberately.
    "AUDIENCE": "my-service",
}

ISSUERS and AUDIENCE are the required keys. Each entry is selected by its kind (jwks_uri, jwks_dict, rsa, or rsa_file). For the full settings shape — issuers, static tokens, provenance, headers, the public API and error model — see docs/USAGE.md.

Upgrading? 4.0 renames the active_org claim to org (which now carries the organization id, not a slug) and makes AUDIENCE and the token's aud claim required. 3.0 fixed two authentication bypasses and contains breaking changes of its own (most notably: token roles are no longer mirrored onto Django Groups). See docs/UPGRADING.md.

Standard Usage

Koherent is designed to work with Strawberry, so you will need to add its extension to your schema.

from authentikate.utils import authenticate_header_or_none


def my_view(request: HttpRequest) -> None:
    auth = authenticate_header_or_none(request.headers)

    if auth:
        auth.user # This is the user that is authenticated
        auth.app # This is the app that is authenticated
        auth.scopes # These are the scopes that are authenticated

GraphQL Setup

Currently we require that you use the Kante GraphQL library, as it provides some boilerplate code that is required to make this work.

import strawberry
from authentikate.strawberry import AuthentikateExtension, AuthExtension

schema = strawberry.Schema(query=Query, extensions=[AuthentikateExtension])


@strawberry.type
class Query:

    @strawberry.field(extensions=[AuthExtension()])
    def me(self, info: Info) -> User:
        return info.context.request.user

    @strawberry.field(extensions=[AuthExtension(scopes=["read:users"])])
    def users(self, info: Info) -> List[User]:
        return User.objects.all()

AuthExtension accepts scopes, roles, any_scope_of and any_role_of. Use AuthSubscribeExtension on subscription fields.

Scoped Members

A member who was shared a few objects of an organization, and nothing else, gets a token with an objects claim, keyed by the hub that hosts them:

{"org": "12", "roles": [], "objects": {"3": ["@mikro/arraydataset:42#derived~8"]}}

Each grant is <structure>:<id>[#<reach>][~<sharer>]: the object, how far the share reaches beyond it (self when left out), and who shared it (~8: user 8's sub).

token.is_scoped tells the two kinds of member apart, and token.grants_for(hub) lists the shared objects as ObjectGrant(structure, object_id, reach, sharer). Which rows an object and its reach cover is the hosting service's business: authentikate only decides whether such a token is served at all.

A grant reaches no further than its sharer. The issuer leaves out the grants of a sharer who is no longer a full member; and where a sharer's membership in this service is blocked, the GraphQL extension drops their grants from the request's token (authentikate.expand.anarrow_scoped_token) before anything reads it.

AUTHENTIKATE = {
    ...,
    "HUB": "3",               # this service's hub: the entry of `objects` it reads
    "SCOPED_TOKENS": "auto",  # auto | reject | self
}
  • auto (the default) rejects a scoped token (SCOPED_TOKEN_UNSUPPORTED) unless something in the process narrows reads to the shared objects and has said so with authentikate.scoped.enforce_scoped(). Where it is accepted, it is read-only: mutations and subscriptions are refused (SCOPED_READ_ONLY) unless every root field opted in with AuthExtension(allow_scoped=True).
  • reject always rejects it.
  • self accepts it and leaves every rule to the service itself.

A share can also permit a write. AuthExtension(any_role_of=["editor"], shared_by=["@mikro/scene#annotate"]) opens the mutation to scoped members holding a grant of a listed structure (anyone else gets SCOPED_READ_ONLY). For them, the field's roles are not theirs to hold but their sharer's: the resolver must check that the object it writes to is shared at that reach, and that the grant's sharer holds those roles (arkitekt_service.sharing.require_shared, which raises SHARE_INSUFFICIENT). Full members are checked against the roles as before.

The schema says all of it. @auth publishes every requirement (required_*, any_*, allow_scoped), and @shared(by: [...]), in grant notation, says which shares permit a mutation. arkitekt-service adds it to types and their fields (which share reveals a type, which reach of the parent's share reveals a field):

type Scene @shared(by: ["@mikro/scene"]) {
  annotations: [Annotation!]! @shared(by: ["#annotate"])
}
type Mutation {
  createAnnotation(input: CreateAnnotationInput!): Annotation!
    @auth(any_role_of: ["admin", "editor", "bot"], allow_scoped: true)
    @shared(by: ["@mikro/scene#annotate", "@mikro/annotationcollection#annotate"])
}

Outside GraphQL, require_full_member(token) and the @full_members_only view decorator refuse a scoped member (FULL_MEMBERSHIP_REQUIRED).

The refusal is recorded as the operation's validation errors (on_validate). An extension that assigns execution_context.pre_execution_errors itself, such as strawberry's ValidationCache, must come before AuthentikateExtension in the schema's extensions, or it overwrites the refusal.

Static Tokens

Static Tokens are tokens that are hard coded into the settings. They are useful for testing and development, but should not be used in production.

AUTHENTIKATE = {
    "ISSUERS": [
        {
            "kind": "jwks_uri",
            "iss": "https://lok.my-org.com",
            "jwks_uri": "https://lok.my-org.com/.well-known/jwks.json",
        }
    ],
    # Static tokens bypass signature verification entirely. They are for tests
    # and local development only: configuring them while DEBUG is False raises
    # ImproperlyConfigured at startup.
    "STATIC_TOKENS": {
        "my_token": {
            "sub": "my_user",
            "iss": "https://lok.my-org.com",
            "scope": "read:users",
            "roles": ["reader"],
        }
    }
}

Metadata

Release files for authentikate 4.4.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for authentikate 4.4.2
File Size Uploaded
authentikate-4.4.2.tar.gz 54.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for authentikate 4.4.2
File Interpreter ABI Platform
authentikate-4.4.2-py3-none-any.whl Python 3 none any Details

Total release size: 121.4 kB

Release files / authentikate-4.4.2.tar.gz

Download URL authentikate-4.4.2.tar.gz
Size 54.2 kB
Tags Source
SHA-256 checksum
How to use checksums
fa18d1b945b457049a0faa94cf6e1c619cbb2473a9fbb0b9a5ea5fa0895b47e2
BLAKE2b-256 checksum
How to use checksums
d1aceec211167224d1c54ce5e9166cdf9a3b4381797f9648e3443b78050a4500
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / authentikate-4.4.2-py3-none-any.whl

Download URL authentikate-4.4.2-py3-none-any.whl
Size 67.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
15e670bf1cd2c536c0dbc2f6c2c773edd0b61dc8ac49c0ee6d0f977f6245e0b2
BLAKE2b-256 checksum
How to use checksums
3d6115258da6904c400614e5fec6956e400b85c99095b559a14aa095213ee081
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

5.0.0

2 release files

This release

4.4.2 This release

2 release files

4.4.1

2 release files

4.4.0

2 release files

4.3.0

2 release files

4.2.0

2 release files

4.1.1

2 release files

4.1.0

2 release files

4.0.1

2 release files

4.0.0

2 release files

3.2.0

2 release files

3.1.0

2 release files

3.0.0

2 release files

2.2.1

2 release files

2.2.0

2 release files

2.1.2

2 release files

2.1.1

2 release files

2.1.0

2 release files

2.0.1

2 release files

2.0.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.32.0

2 release files

0.31.0

2 release files

0.28.0

2 release files

0.26.0

2 release files

0.25.0

2 release files

0.23.0

2 release files

0.22.0

2 release files

0.21.1

2 release files

0.21.0

2 release files

0.20.0

2 release files

0.19.0

2 release files

0.18.2

2 release files

0.18.1

2 release files

0.18.0

2 release files

0.17.1

2 release files

0.17.0

2 release files

0.16.0

2 release files

0.15.0

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page