Command-line OAuth2 authentication daemon

Related tags

Command-line pizauth
Overview

pizauth: a background OAuth2 token requester

pizauth is a simple program for obtaining, handing out, and refreshing OAuth2 access tokens. pizauth is formed of two components: a persistent server which interacts with the user to obtain tokens, and refreshes them as necessary; and a command-line interface which can be used by programs such as fdm and msmtp to display OAuth2 access tokens. Tokens are only ever stored in memory and are never persisted to disk.

Quick setup

pizauth's configuration file is ~/.config/pizauth.conf. You need to specify at least one account, which tells pizauth how to authenticate against a particular OAuth2 setup. At a minimum you need to find out from your provider:

  • The authorisation URI.
  • The token URI.
  • Your "Client ID" (and in many cases also your "Client secret"), which identify your software.
  • The scope(s) which your OAuth2 access token will give you access to. For pizauth to be able to refresh tokens, you may need to add an explicit offline_access scope.
  • (In some cases) The redirect URI (you must copy this exactly, including trailing slash / characters). The default value of http://localhost/ suffices in most instances.

Some providers allow you to create Client IDs and Client Secrets at will (e.g. Google). Some providers sometimes allow you to create Client IDs and Client Secrets (e.g. Microsoft Azure but allow organisations to turn off this functionality.

For example, to create an account called officesmtp which obtains OAuth2 tokens which allow you to read email via IMAP and send email via Office365's servers:

account "officesmtp" {
    auth_uri = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
    token_uri = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
    client_id = "..."; // Fill in with your Client ID
    client_secret = "..."; // Fill in with your Client secret
    scopes = [
      "https://outlook.office365.com/IMAP.AccessAsUser.All",
      "https://outlook.office365.com/SMTP.Send",
      "offline_access"
    ];
    // You don't have to specify login_hint, but it does make authentication a
    // little easier.
    login_hint = "[email protected]";
}

You then need to run the pizauth server:

$ pizauth server

and configure software to request OAuth2 tokens with pizauth show officesmtp. The first time that pizauth show officesmtp is executed, it will print an error to stderr that includes an authorisation URL:

$ pizauth show officesmtp
ERROR - Token unavailable until authorised with URL https://login.microsoftonline.com/common/oauth2/v2.0/authorize?access_type=offline&code_challenge=xpVa0mDzvR1Ozw5_cWN43DsO-k5_blQNHIzynyPfD3c&code_challenge_method=S256&scope=https%3A%2F%2Foutlook.office365.com%2FIMAP.AccessAsUser.All+https%3A%2F%2Foutlook.office365.com%2FSMTP.Send+offline_access&client_id=<your Client ID>&redirect_uri=http%3A%2F%2Flocalhost%3A14204%2F&response_type=code&state=%25E6%25A0%25EF%2503h6%25BCK&client_secret=<your Client Secret>&[email protected]

The user then needs to open that URL in the browser of their choice and complete authentication. Once complete, pizauth will be notified, and shortly afterwards pizauth show officesmtp will start showing a token on stdout:

$ pizauth show officesmtp
DIASSPt7jlcBPTWUUCtXMWtj9TlPC6U3P3aV6C9NYrQyrhZ9L2LhyJKgl5MP7YV4

Note that:

  1. pizauth show does not block: if a token is not available it will fail; once a token is available it will succeed.
  2. pizauth show can print OAuth2 tokens which are no longer valid. By default, pizauth will continually refresh your token, but it may eventually become invalid. There will be a delay between the token becoming invalid and pizauth realising that has happened and notifying you to request a new token.

Notifications

Authorisation notifications

By default, pizauth show displays authorisation URLs. If you prefer to be notified asynchronously, pizauth can run arbitrary commands to alert you that you need to authorise a new token. You will first probably want to use show -u to suppress display of autherisation URLs:

$ pizauth show -u officesmtp
ERROR - Token unavailable until authorised with URL

You can then specify the global auth_notify_cmd setting e.g.:

auth_notify_cmd = "notify-send -t 30000 'pizauth authentication' \"<a href=\\\"`echo $PIZAUTH_URL | sed 's/&/&amp;/g'`\\\">$PIZAUTH_ACCOUNT</a>\"";

When refresh or show initiate a new token request, auth_notify_cmd is run with two environment variables set:

  • PIZAUTH_ACCOUNT is set to the account name to be authorised.
  • PIZAUTH_URL is set to the authorisation URL.

In the example above, notify-send is invoked, escaping & characters, as XFCE's notification daemon otherwise does not parse URLs correctly. As this suggests, users have complete flexibility within auth_notify_cmd to run arbitrary shell commands.

If auth_notify_cmd is specified, then pizauth will periodically run auth_notify_cmd for a given account until authorisation concludes (successfully or not). The period between notifications is controlled by the global auth_notify_interval = <time>; setting which defaults to 15m (15 minutes).

<time> is an integer followed by one of:

Suffix Value
s seconds
m minutes
h hours
d days

Error notifications

pizauth reports authentication errors via syslog by default. To override this you can set the global auth_error_cmd setting e.g.:

auth_error_cmd = "notify-send -t 90000 \"pizauth error for $PIZAUTH_ACCOUNT\" \"$PIZAUTH_MSG\"";

auth_error_cmd is run with two environment variables set:

  • PIZAUTH_ACCOUNT is set to the account name to be authorised.
  • PIZAUTH_MSG is set to the error message.

Token refresh

OAuth2 "tokens" are actually two separate things: an "access token" which allows you to utilise a resource (e.g. to read/send email); and a "refresh token" which allows you to request new access tokens. pizauth show prints access tokens; pizauth stores refresh tokens internally but never displays them. Access tokens typically have a short lifetime (e.g. 1 hour) while refresh tokens have a long lifetime (e.g. 1 week or more). By default, pizauth uses refresh tokens to preemptively update access tokens, giving users the illusion of continuously usable access tokens.

Each account has two settings relating to token refresh:

  • refresh_before_expiry = <time>; tells pizauth to refresh an access token a unit of time before it is due to expire. The default is 90s (90 seconds).
  • refresh_at_least = <time>; tells pizauth to refresh an access token a unit of time after it was obtained, even if the access token is not due to expire. The default is 90m (90 minutes).

refresh_at_least is a backstop which guarantees that pizauth will notice that an access and refresh token are no longer valid in a sensible period of time.

Refreshing can fail for temporary reasons (e.g. lack of network connectivity). When a refresh fails for temporary reasons, pizauth will regularly retry refreshing, controlled by the global refresh_retry_interval setting which defaults to 40 seconds.

You can set these values explicitly as follows:

refresh_retry_interval = 40s;

account "officesmtp" {
    // Other settings as above
    refresh_before_expiry = 90s;
    refresh_at_least = 90m;
}

Command-line interface

pizauth's usage is:

pizauth refresh [-u] <account>
pizauth reload
pizauth server [-c <config-path>] [-d]
pizauth show [-u] <account>
pizauth shutdown

Where:

  • pizauth refresh tries to obtain a new access token for an account. If an access token already exists, a refresh is tried; if an access token doesn't exist, a new request is made.
  • pizauth reload causes the server to reload its configuration (this is a safe equivalent of the traditional SIGHUP mechanism).
  • pizauth server starts a new instance of the server.
  • pizauth show displays an access token, if one exists, for account. If an access token does not exist, a new request is initiated.
  • pizauth shutdown asks the server to shut itself down.

Example integrations

Once you have set up pizauth, you will then need to set up the software which needs access tokens. This section contains example configuration snippets to help you get up and running.

In these examples, text in chevrons (like <this>) needs to be edited to match your individual setup. The examples assume that pizauth is in your $PATH: if it is not, you will need to substitute an absolute path to pizauth in these snippets.

msmtp

In your config file (typically ~/.config/msmtp/config):

account <account-name>
auth xoauth2
host <smtp-server>
protocol smtp
from <email-address>
user <username>
passwordeval pizauth show <pizauth-account-name>

mbsync

Ensure you have the xoauth2 plugin for cyrus-sasl installed, and then use something like this for the IMAP account in ~/.mbsyncrc:

IMAPAccount <account-name>
Host <imap-server>
User <username>
PassCmd "pizauth show <pizauth-account-name>"
AuthMechs XOAUTH2

Example account settings

Each provider you wish to authenticate with will have its own settings it requires of you. These can be difficult to find, so examples are provided in this section. Caveat emptor: these settings will not work in all situations, and providers have historically required users to intermittently change their settings.

Microsoft / Exchange

account "<your-account-name>" {
    auth_uri = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
    token_uri = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
    client_id = "<your-client-id>";
    client_secret = "<your-client-secret>";
    scopes = [
      "https://outlook.office365.com/IMAP.AccessAsUser.All",
      "https://outlook.office365.com/POP.AccessAsUser.All",
      "https://outlook.office365.com/SMTP.Send",
      "offline_access"
    ];
    login_hint = "<your-email-address>";
}

Gmail

You may need to create your own client ID and secret via the credentials tab of the Google Cloud Console.

account "<your-account-name>" {
    auth_uri = "https://accounts.google.com/o/oauth2/auth";
    token_uri = "https://oauth2.googleapis.com/token";
    client_id = "<your-client-id>";
    client_secret = "<your-client-secret>";
    scopes = ["https://mail.google.com/"];
    login_hint = "<your-email-address>";
}

Alternatives

pizauth will not be perfect for everyone. You may also wish to consider these programs as alternatives:

You might also like...
A full featured, fast Command Line Argument Parser for Rust

clap Command Line Argument Parser for Rust It is a simple-to-use, efficient, and full-featured library for parsing command line arguments and subcomma

Docopt for Rust (command line argument parser).

THIS CRATE IS UNMAINTAINED This crate is unlikely to see significant future evolution. The primary reason to choose this crate for a new project is if

Parse command line arguments by defining a struct.

StructOpt Parse command line arguments by defining a struct. It combines clap with custom derive. Documentation Find it on Docs.rs. You can also check

A command line progress reporting library for Rust
A command line progress reporting library for Rust

indicatif Documentation A Rust library for indicating progress in command line applications to users. This currently primarily provides progress bars

Low-level Rust library for implementing terminal command line interface, like in embedded systems.

Terminal CLI Need to build an interactive command prompt, with commands, properties and with full autocomplete? This is for you. Example, output only

⚡️ Lightning-fast and minimal calendar command line. Written in Rust 🦀
⚡️ Lightning-fast and minimal calendar command line. Written in Rust 🦀

⚡️ Lightning-fast and minimal calendar command line. It's similar to cal. Written in Rust 🦀

Command-Line program that takes images and produces the copy of the image with a thin frame and palette made of the 10 most frequent colors.
Command-Line program that takes images and produces the copy of the image with a thin frame and palette made of the 10 most frequent colors.

paleatra v.0.0.1 Command-Line program that takes an image and produces the copy of the image with a thin frame and palette made of the 10 most frequen

parse command-line arguments into a hashmap and vec of positional args

parse command-line arguments into a hashmap and vec of positional args This library doesn't populate custom structs, format help messages, or convert types.

A tactics trainer for the command line
A tactics trainer for the command line

Chess Tactics CLI Practice some chess tactics in your terminal while you wait for your code to compile. Fetches tactics from this tactics API. Built W

Comments
  • Can't build on macOS because `nix::unistd::daemon` doesn't exist

    Can't build on macOS because `nix::unistd::daemon` doesn't exist

    I don't think this is easily fixable, but I am building on macOS and get:

    error[E0432]: unresolved import `nix::unistd::daemon`
    

    I assume this is because dameon is not included in nix::unistd on macOS (as per this line). I am not a Rust programmer; are there any quick fixes I could make on macOS to solve this?

    Thanks

    opened by samuelstevens 7
  • fix: implement daemon(3) for macOS (fixes #3)

    fix: implement daemon(3) for macOS (fixes #3)

    It builds on macOS now! I'll be honest, I don't know if it works on macOS, but the tests pass and the application successfully daemonizes if run like this:

    cargo run -- server -c ./pizauth.conf.example
    

    Here's a screenshot from Activity Monitor (macOS 12.6, AArch64) after running this command:

    pizauth, shown as running in macOS's activity monitor


    I'm not sure about creating mod compat in src/main.rs. I had originally created src/compat.rs, but I decided that all of the ![cfg(target_os = "macos")] imports were better handled at the module level. Let me know what you think!

    Fixes #3

    opened by eddieantonio 6
Owner
Laurence Tratt
Programmer, researcher. Software Development Team, King's College London
Laurence Tratt
Small command-line tool to switch monitor inputs from command line

swmon Small command-line tool to switch monitor inputs from command line Installation git clone https://github.com/cr1901/swmon cargo install --path .

William D. Jones 5 Aug 20, 2022
Command-line HTTP client for sending a POST request to specified URI on each stdin line.

line2httppost Simple tool to read lines from stdin and post each line as separate POST request to a specified URL (TCP connection is reused though). G

Vitaly Shukela 3 Jan 3, 2023
⏳ trackie is a private, daemon-less time tracker for your CLI.

⏳ trackie `trackie` is a private, daemon-less time tracker running in your CLI. Trackie offers an easy CLI to track the time you spent on your various

Christoph Loy 40 Dec 14, 2022
Pink is a command-line tool inspired by the Unix man command.

Pink is a command-line tool inspired by the Unix man command. It displays custom-formatted text pages in the terminal using a subset of HTML-like tags.

null 3 Nov 2, 2023
Authentication workaround for N-Central Report Manager

reportlinkfix Authentication workaround for N-Central Report Manager. Takes the link that N-Central creates for Report Manager and outputs a working l

501 Commons 1 Jan 31, 2022
This PAM module provides ssh-agent based authentication

PAM-RSSH This PAM module provides ssh-agent based authentication. The primary design goal is to avoid typing password when you sudo on remote servers.

Yuxiang Zhang 21 Dec 14, 2022
Galileo OSNMA (Open Service Navigation Message Authentication)

galileo-osnma galileo-osnma is a Rust implementation of the Galileo OSNMA (Open Service Navigation Message Authentication) protocol. This protocol is

Daniel Estévez 26 Nov 25, 2022
Over-simplified, featherweight, open-source and easy-to-use authentication and authorization server.

concess ⚠️ Early Development: This is not production ready, yet. Do not use it for anything important. Introduction concess is a over-simplified, feat

Dustin Frisch 3 Nov 25, 2022
Authentication and authorization service, written in Rust

auth-rs auth-rs provides a simple authentication and authorization service for use in other services. The service is written in Rust and uses the acti

OpServa 3 Aug 17, 2023
Checkline: checkbox line picker for stdin line input

checkline is a Unix command line interface (CLI) terminal user interface (TUI) that prompts you to check each line of stdin, to pick each line to output to stdout

SixArm 4 Dec 4, 2022