Check a polkit Authorisation Safely with pkcheck
This guide shows you how to ask polkit whether a process may perform a named action, read the result in a script, and avoid the process-identity race that makes short PID forms unsafe. The examples use pkcheck 124 from polkitd 124-2ubuntu1.24.04.4, installed on Ubuntu 24.04 here. Allow about 10 minutes if you already know the action ID; finding the right policy action is usually the slower part.
The route
Jump straight to the step you need, or tick off Done means at the end.
- Before you start
- 1. Build a race-resistant process subject
- 2. Check an action without opening an authentication prompt
- 3. Allow interaction only when a person is present
- 4. Pass action details when policy needs context
- 5. Check a D-Bus service instead of a PID
- 6. Inspect or revoke temporary authorisations
- Common traps
Before you start
You need a running polkit service and the pkcheck command. You do not normally need root to check the authorisation of your own process. The action ID must come from the application or policy you are investigating. Do not guess one and treat a result as proof of a different operation.
List installed actions with pkaction. This is read-only and may produce a long report:
pkaction --verbose | less
Find the exact action ID, then inspect its policy fields, especially the active-session result. A policy can allow, deny, or require authentication depending on the subject and session.
Checkpoint
Write down one exact action ID, such as org.freedesktop.policykit.exec, before continuing. That example is useful for testing the command but commonly requires administrator authentication.
1. Build a race-resistant process subject
For a process check, pkcheck accepts a PID, an optional start time, and an optional UID. The manual warns against both the bare PID and the PID plus start-time forms: a process can exit and its PID can be reused between collecting the value and checking it. New code should provide all three values.
This shell snippet targets the shell running the snippet. It extracts the process start time from /proc and adds the current UID:
pid=$$
start_time=$(awk -F') ' '{print $2}' "/proc/$pid/stat" | awk '{print $20}')
uid=$(id -u)
printf 'pid=%s start_time=%s uid=%s\n' "$pid" "$start_time" "$uid"
The second awk is deliberate. The process name in /proc/PID/stat is enclosed in parentheses and may contain spaces, so splitting the whole line on whitespace is not a reliable general parser.
Checkpoint
Confirm that all three values are non-empty and numeric. If /proc/$pid/stat cannot be read, the process has probably already ended; collect the values again rather than weakening the subject.
2. Check an action without opening an authentication prompt
Pass the action ID and the complete process subject. The command below checks the example action for the shell that collected the values:
action_id=org.freedesktop.policykit.exec
pkcheck --action-id "$action_id" --process "$pid,$start_time,$uid"
check_status=$?
printf 'pkcheck exit status: %s\n' "$check_status"
On this machine, the example returned exit status 2 and printed Authorization requires authentication and -u wasn't passed. on standard error. That is a meaningful answer, not a command failure: pkcheck could not authorise the action without an authentication interaction.
Use the status immediately. The documented meanings are:
0: the process is authorised. Any returned details are printed asKEY=VALUElines on standard output.1: the process is not authorised.2: authorisation needs interaction, but no interaction was allowed, or no suitable agent is available.3: an authentication request was dismissed.126: an option was malformed.127: an error occurred while checking authorisation.
Do not collapse every non-zero result into "denied". Status 2 means that a policy decision may still be possible after authentication, while status 1 is an actual refusal.
3. Allow interaction only when a person is present
Add --allow-user-interaction when an interactive tool is allowed to wait for the registered authentication agent:
pkcheck --action-id "$action_id" \
--process "$pid,$start_time,$uid" \
--allow-user-interaction
This can display an authentication request and block until it completes. It is unsuitable for unattended jobs unless the wait and failure paths are explicitly handled. Never add it merely to make a script return success: doing so can turn a quick policy probe into a hanging service or an unexpected password prompt.
If the process has no suitable desktop agent, --enable-internal-agent asks pkcheck to register its own textual agent. That still requires a usable terminal and user interaction. It does not bypass policy or grant permission.
4. Pass action details when policy needs context
Some policies use details supplied by the caller. Add each key and value with --detail; do not place arbitrary shell text in a value without quoting it:
pkcheck --action-id "$action_id" \
--process "$pid,$start_time,$uid" \
--detail example-key 'example-value'
The accepted keys and their meanings belong to the action's policy and caller documentation. A detail does not override the policy. If the action does not use it, the check may produce the same decision.
5. Check a D-Bus service instead of a PID
When the operation belongs to a D-Bus service, use its system bus name rather than trying to identify a transient worker process:
pkcheck --action-id 'ACTION_ID_FROM_PKACTION' \
--system-bus-name 'org.example.Service'
Replace both placeholders with values documented by that service. The bus-name subject is different from the process subject, so do not mix the two forms in one invocation.
6. Inspect or revoke temporary authorisations
These operations apply to the current session and change authorisation state. Listing is read-only:
pkcheck --list-temp
On a session with no temporary grants this produced no output and exit status 0 here. If it lists grants, treat the output as security-sensitive session information.
Warning
--revoke-temp revokes all temporary authorisations for the current session. It does not undo a configuration change or restore an earlier grant. The action is not selective, and there is no pkcheck undo command. Use it only when you intend to invalidate every temporary grant; affected applications must authenticate again when their policies require it.
Common traps
- Using
$$after a command has changed the shell context. Capture the PID, start time, and UID together immediately before the check. - Reading only standard output. Diagnostics and authentication messages go to standard error, while policy details go to standard output.
- Using
--allow-user-interactionin a daemon or CI job. Prefer a non-interactive check and handle status 2 explicitly. - Assuming root makes every action authorised. The result still depends on polkit policy, subject details, and session state.
- Confusing pkcheck with an action runner. It checks authorisation; it does not execute the protected operation.
Done means
- You identified the exact action ID from installed policy or the owning application.
- Your process check used
pid,start-time,uid, not a bare PID. - Your script records and interprets pkcheck status 0, 1, 2, 3, 126, and 127 separately where that distinction matters.
- You used authentication interaction only in a deliberately interactive context.
- You treated
--revoke-tempas a session-wide, irreversible authorisation change.