# 🔑 Ortie [![Releases](https://img.shields.io/github/v/release/pimalaya/ortie?color=success)](https://github.com/pimalaya/ortie/releases/latest) [![Repology](https://img.shields.io/repology/repositories/ortie?color=success)]("https://repology.org/project/ortie/versions) [![Matrix](https://img.shields.io/badge/chat-%23pimalaya-blue?style=flat&logo=matrix&logoColor=white)](https://matrix.to/#/#pimalaya:matrix.org) [![Mastodon](https://img.shields.io/badge/news-%40pimalaya-blue?style=flat&logo=mastodon&logoColor=white)](https://fosstodon.org/@pimalaya)

CLI to manage OAuth tokens

## Table of contents

- [Features](#features)
- [Installation](#installation)
- [Configuration](#configuration)
  - [Google](#google)
  - [Microsoft](#microsoft)
- [Usage](#usage)
  - [Request new access token](#request-new-access-token)
  - [Refresh access token](#refresh-access-token)
  - [Show access token](#show-access-token)
- [Alternatives](#alternatives)
- [FAQ](#faq)
- [Social](#social)
- [Sponsoring](#sponsoring)

## Features

- **OAuth 2.0** support:
  - Authorization Code Grant <sup>[rfc6749 #4.1](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1)</sup>
  - Refreshing an access token <sup>[rfc6749 #6](https://datatracker.ietf.org/doc/html/rfc6749#section-6)</sup>
- **PKCE** support <sup>[rfc7636](https://datatracker.ietf.org/doc/html/rfc7636)<sup>
- Native TLS support via [native-tls](https://crates.io/crates/native-tls) crate (requires `native-tls` feature)
- Rust TLS support via [rustls](https://crates.io/crates/rustls) crate with:
  - AWS crypto support (requires `rustls-aws` feature)
  - Ring crypto support (requires `rustls-ring` feature)
- Fake HTTP **redirection server**
- Shell command and keyring **storages** (requires `command` and `keyring` features)
- Shell command and system notification **hooks** (requires `command` and `notify` features)
- **JSON** support with `--json`

*Ortie CLI is written in [Rust](https://www.rust-lang.org/), and relies on [cargo features](https://doc.rust-lang.org/cargo/reference/features.html) to enable or disable functionalities. Default features can be found in the `features` section of the [`Cargo.toml`](https://github.com/pimalaya/ortie/blob/master/Cargo.toml#L18), or on [docs.rs](https://docs.rs/crate/ortie/latest/features).*

## Installation

### Pre-built binary

Ortie CLI can be installed with the installer:

*As root:*

```
curl -sSL https://raw.githubusercontent.com/pimalaya/ortie/master/install.sh | sudo sh
```

*As a regular user:*

```
curl -sSL https://raw.githubusercontent.com/pimalaya/ortie/master/install.sh | PREFIX=~/.local sh
```

These commands install the latest binary from the GitHub [releases](https://github.com/pimalaya/ortie/releases) section.

If you want a more up-to-date version than the latest release, check out the [releases](https://github.com/pimalaya/ortie/actions/workflows/releases.yml) GitHub workflow and look for the *Artifacts* section. You should find a pre-built binary matching your OS. These pre-built binaries are built from the `master` branch, using default features.

### Cargo

Ortie CLI can be installed with [cargo](https://doc.rust-lang.org/cargo/):

```
cargo install ortie
```

You can also use the git repository for a more up-to-date (but less stable) version:

```
cargo install --locked --git https://github.com/pimalaya/ortie.git
```

### Nix

Ortie CLI can be installed with [Nix](https://serokell.io/blog/what-is-nix):

```
nix-env -i ortie
```

You can also use the git repository for a more up-to-date (but less stable) version:

```
nix-env -if https://github.com/pimalaya/ortie/archive/master.tar.gz
```

*Or, from within the source tree checkout:*

```
nix-env -if .
```

If you have the [Flakes](https://nixos.wiki/wiki/Flakes) feature enabled:

```
nix profile install ortie
```

*Or, from within the source tree checkout:*

```
nix profile install
```

*You can also run Ortie directly without installing it:*

```
nix run ortie
```

## Configuration

The wizard is not yet available (it should come soon), meanwhile you can manually edit your own configuration from scratch:

- Copy the content of the documented [`./config.sample.toml`](./config.sample.toml)
- Paste it into a new file `~/.config/ortie/config.toml`
- Edit, then comment or uncomment the options you want

You will also need a registered application. This depends on your OAuth 2.0 provider. You can either use an existing application (public registration like Thunderbird) or register your own application. The first option is definitely simpler.

*See public Thunderbird application credentials for various providers at [github.com/mozilla](https://github.com/mozilla/releases-comm-central/blob/master/mailnews/base/src/OAuth2Providers.sys.mjs).*

### Google

```toml
endpoints.authorization = "https://accounts.google.com/o/oauth2/auth?access_type=offline"
endpoints.token = "https://www.googleapis.com/oauth2/v3/token"
scopes = ["https://www.googleapis.com/auth/carddav", "https://mail.google.com"] # choose the right scope for your usage
```

Using public Thunderbird application:

```toml
client-id = "406964657835-aq8lmia8j95dhl1a2bvharmfk3t1hgqj.apps.googleusercontent.com"
client-secret.raw = "kSmqreRr0qwBWJgbf5Y-PjSU"
enpoints.redirection = "http://localhost"
```

Using your [own application](https://developers.google.com/identity/protocols/oauth2):

```toml
client-id = "<your-client-id>"
client-secret = "<your-client-secret>"
```

### Microsoft

```toml
endpoints.authorization = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
endpoints.token = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
```

Using public Thunderbird application:

```toml
client-id = "9e5f94bc-e8a4-4e73-b8be-63364c29d753"
endpoints.redirection = "https://localhost"
```

Using your [own application](https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth):

```toml
client-id = "<your-client-id>"
client-secret = "<your-client-secret>"
```

## Usage

### Request new access token

```
$ ortie auth get

Created authorization request with:
 - state: RWdzST0ybUIzT1wtMSF9OCMmJHJUVmJrUmhhU0haLz4
 - pkce: oJ-rEXNu9YzqpCWVIPOwD5KvMhLAT73dstk0jye8nZ6

Sending authorization request to your browser…
Spawning fake HTTP redirection server…
Waiting for redirection…
```

Go to your browser, follow the instructions, then you should see:

```
Authorization succeeded!
```

Go back to your terminal, you should see:

```
Continue authorization process…
Access token successfully issued (expires in 1h)
```

In case the redirections fails, for example:

```
$ ortie auth get

Created authorization request with:
 - state: RWdzST0ybUIzT1wtMSF9OCMmJHJUVmJrUmhhU0haLz4
 - pkce: oJ-rEXNu9YzqpCWVIPOwD5KvMhLAT73dstk0jye8nZ6

Sending authorization request to your browser…
Spawn fake HTTP redirection server…
Error: Permission denied (os error 13)
```

Go to your browser, follow the instructions, then copy the URL you are redirected to (it should fail since the fake HTTP redirection server did not start).

Go back to your terminal, and complete the authorization flow:

```
ortie auth resume \
  --state RWdzST0ybUIzT1wtMSF9OCMmJHJUVmJrUmhhU0haLz4 \
  --pkce oJ-rEXNu9YzqpCWVIPOwD5KvMhLAT73dstk0jye8nZ6 \
  https://localhost/?code=M.C521_BAY.2.U&state=RWdzST0ybUIzT1wtMSF9OCMmJHJUVmJrUmhhU0haLz4
```

### Refresh access token

```
$ ortie token refresh

Access token successfully refreshed (expires in 1h)
```

### Show access token

```
$ ortie token show

EwA4BOl3BAAUcDnR9grBJokeAHaUV8R3+rVHX+IAAQfw9oZLztQS8bo8NvyWmbs…
```

The `--auto-refresh` argument (as well as the config option `auto-refresh = true`) automatically refreshes expired tokens.

You can also inspect token metadata:

```
$ ortie token inspect

Token type: bearer
Issued: 22h 51m 1s ago
Expires in: 52m 38s
With refresh token: true
With scope: https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send
```

## Alternatives

- [pizauth](https://github.com/ltratt/pizauth): daemon-oriented alternative
- [oama](https://github.com/pdobsan/oama): haskell alternative
- [mutt_oauth2.py](https://gitlab.com/muttmua/mutt/-/blob/master/contrib/mutt_oauth2.py): python script alternative

## FAQ

### How to debug Ortie CLI?

The simplest way is to use `--debug` and/or `--trace` arguments.

The advanced way is based on environment variables:

- `RUST_LOG=<level>`: determines the log level filter, can be one of `off`, `error`, `warn`, `info`, `debug` and `trace`.
- `RUST_BACKTRACE=1`: enables the full error backtrace, which include source lines where the error originated from.

Logs are written to the `stderr`, which means that you can redirect them easily to a file:

```
ortie token show --debug 2>/tmp/ortie.log
```

## Social

- Chat on [Matrix](https://matrix.to/#/#pimalaya:matrix.org)
- News on [Mastodon](https://fosstodon.org/@pimalaya) or [RSS](https://fosstodon.org/@pimalaya.rss)
- Mail at [pimalaya.org@posteo.net](mailto:pimalaya.org@posteo.net)

## Sponsoring

[![nlnet](https://nlnet.nl/logo/banner-160x60.png)](https://nlnet.nl/)

Special thanks to the [NLnet foundation](https://nlnet.nl/) and the [European Commission](https://www.ngi.eu/) that have been financially supporting the project for years:

- 2022: [NGI Assure](https://nlnet.nl/project/Himalaya/)
- 2023: [NGI Zero Entrust](https://nlnet.nl/project/Pimalaya/)
- 2024: [NGI Zero Core](https://nlnet.nl/project/Pimalaya-PIM/) *(still ongoing in 2026)*

If you appreciate the project, feel free to donate using one of the following providers:

[![GitHub](https://img.shields.io/badge/-GitHub%20Sponsors-fafbfc?logo=GitHub%20Sponsors)](https://github.com/sponsors/soywod)
[![Ko-fi](https://img.shields.io/badge/-Ko--fi-ff5e5a?logo=Ko-fi&logoColor=ffffff)](https://ko-fi.com/soywod)
[![Buy Me a Coffee](https://img.shields.io/badge/-Buy%20Me%20a%20Coffee-ffdd00?logo=Buy%20Me%20A%20Coffee&logoColor=000000)](https://www.buymeacoffee.com/soywod)
[![Liberapay](https://img.shields.io/badge/-Liberapay-f6c915?logo=Liberapay&logoColor=222222)](https://liberapay.com/soywod)
[![thanks.dev](https://img.shields.io/badge/-thanks.dev-000000?logo=data:image/svg+xml;base64, )](https://thanks.dev/soywod)
[![PayPal](https://img.shields.io/badge/-PayPal-0079c1?logo=PayPal&logoColor=ffffff)](https://www.paypal.com/paypalme/soywod)
