Hijack permission

By default, only superusers are allowed to hijack other users. This behavior can be adapted to your liking. However, be aware of the potential secuirty implications.

You alter the permission check, including that of the can_hijack template tag via the HIJACK_PERMISSION_CHECK setting.

The setting is a dotted/Python path to permission function. The function must accept two keyword arguments hijacker and hijacked. Default: 'hijack.permissions.superusers_only'.

Builtin permission functions

We provide a couple of builtin permission functions for your convenience.


A superuser may hijack any other user (except inactive once). Used by default.


Superusers and staff members may hijack other users (except inactive once).

A superuser may hijack any other user. A staff member may hijack any user, except another staff member or superuser.

Can be enabled by changing your settings to:

HIJACK_PERMISSION_CHECK = "hijack.permissions.superusers_and_staff"

Custom permission functions

Advanced Django developers might want to define their own check whether a user may hijack another user. This can be achieved by writing a custom permission function. The function must accept two keyword arguments hijacker and hijacked and return a boolean value. Example:

# mysite/

def hijack_superusers_only(*, hijacker, hijacked):
    """Only superusers may hijack other users."""
    return hijacked.is_active and hijacker.is_superuser

def hijack_staff_other_staff(*, hijacker, hijacked):
    """Staff members may hijack other staff and regular users, but not superusers."""
    if not hijacked.is_active:
        return False

    if hijacker.is_superuser:
        return True

    if hijacker.is_staff and not hijacked.is_superuser:
        return True

Warning: Writing custom permission check functions is highly dangerous. If you create your own permission check, make sure to test your implementation against all possible scenarios to prevent permission escalation.

Hijacking inactive users (i.e. users with is_active=False) is not allowed to prevent dead locks, since an inactive user cannot be released.

Notification Layout

There is no "one size fits all" solution, when it comes to the notification layout. Therefore, it is recommened to create your own template and adapt the notification to your site specific layout.

Create a template called hijack/notification.html in your template folder.

Use may use the default template as a cheat-sheet. If you are experiencing trouble, please refer to Django's guide on overriding templates.

<!-- hijack/notification.html -->
<link rel="stylesheet" type="text/css" href="{% static 'hijack/hijack.min.css' %}" media="screen">
<div class="djhj" id="djhj">
  <div class="djhj-notification">
    <div class="djhj-message">
      {% blocktrans trimmed with user=request.user %}
        You are currently working on behalf of <em>{{ user }}</em>.
      {% endblocktrans %}
    <form action="{% url 'hijack:release' %}" method="POST" class="djhj-actions">
      {% csrf_token %}
      <input type="hidden" name="next" value="{{ request.path }}">
      <button class="djhj-button" onclick="document.getElementById('djhj').style.display = 'none';" type="button">
        {% trans 'hide' %}
      <button class="djhj-button" type="submit">
        {% trans 'release' %}

The next field is optional as well, but with a different default. If not provided a user will be forwarded to the LOGOUT_REDIRECT_URL.

Identifying hijacked users

A hijacked user can be identified in you template or application via request.user.is_hijacked. This attribute will be true for hijacked users.



Alters at which point of the DOM the notification is injected. The notification will not be injected if set to None.

Warning: Hiding the notification increases the risk of undeliberate action. Ensure your project has its own notification mechanism before setting this to None.

Default: </body>.


Dotted path of a function checking whether hijacker is allowed to hijack hijacked. The function must accept two keyword arguments hijacker and hijacked.

Default: 'hijack.permissions.has_hijack_perm'.


You can catch a signal when someone is hijacked or released. Here is an example:

from hijack import signals

def print_hijack_started(sender, hijacker, hijacked, request, **kwargs):
    print('%d has hijacked %d' % (hijacker, hijacked))

def print_hijack_ended(sender, hijacker, hijacked, request, **kwargs):
    print('%d has released %d' % (hijacker, hijacked))