Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ permissions:
# If there's a prerelease-style suffix to the version, then the release(s)
# will be marked as a prerelease.
on:
workflow_dispatch:
pull_request:
push:
tags:
- '**[0-9]+.[0-9]+.[0-9]+*'
- 'v*.*.*'

jobs:
# Run 'dist plan' (or host) to determine what tasks we need to do
Expand Down
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
## [Unreleased]
- Nothing yet.

## [0.2.10] - 2026-05-03
### Added
- Optional cookie authentication mode using `TOKEN_V2` and `REDDIT_SESSION` from an existing browser session.
- Cookie auth setup documentation and a `cookie_probe` example for checking credentials before opening the TUI.
### Fixed
- Apple Terminal now disables Kitty image escape output automatically.

## [0.2.9] - 2025-11-05
### Added
- Optional `ui.cell_width` and `ui.cell_height` overrides so you can pin custom terminal cell metrics when needed.
Expand Down Expand Up @@ -164,7 +171,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
### Added
- Initial release with the polished login workflow, refreshed caching, and improved feed pagination.

[Unreleased]: https://github.com/ck-zhang/reddix/compare/v0.2.9...HEAD
[Unreleased]: https://github.com/natekettles/reddix/compare/v0.2.10...HEAD
[0.2.10]: https://github.com/natekettles/reddix/compare/v0.2.9...v0.2.10
[0.2.9]: https://github.com/ck-zhang/reddix/compare/v0.2.8...v0.2.9
[0.2.8]: https://github.com/ck-zhang/reddix/compare/v0.2.7...v0.2.8
[0.2.7]: https://github.com/ck-zhang/reddix/compare/v0.2.6...v0.2.7
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "reddix"
version = "0.2.9"
version = "0.2.10"
edition = "2021"
license = "MIT"
description = "Reddix - Reddit, refined for the terminal."
Expand Down
107 changes: 75 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,62 +1,105 @@
# Reddix
# Reddix Cookie Auth Fork

[![Release](https://img.shields.io/github/v/release/ck-zhang/reddix?style=flat-square)](https://github.com/ck-zhang/reddix/releases/latest)
[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](LICENSE)
This is a fork of [ck-zhang/reddix](https://github.com/ck-zhang/reddix) that adds a personal-use cookie authentication mode. Thanks to [ck-zhang](https://github.com/ck-zhang) for creating Reddix.

The upstream Reddix app uses Reddit OAuth. This fork can instead read your existing browser Reddit cookies from environment variables and use them to load Reddit in the terminal. This is not an official or Reddit-approved authentication method. Abuse, unusual traffic, or detection by Reddit could result in rate limiting, session invalidation, or an account ban.

Reddix - Reddit, refined for the terminal.

![Reddix UI](docs/assets/reddix-ui-preview.png)

## Features
## Cookie Auth Quickstart

- Image previews based on the kitty graphics protocol
- Video playback via [mpv](https://mpv.io)'s Kitty integration
- Gallery browsing with inline navigation controls
- Multi-account support
- Keyboard-first navigation
- Smart caching
- NSFW filter toggle
For the best experience, run Reddix in a terminal that supports the Kitty graphics protocol. [Ghostty](https://ghostty.org/) is a good choice on macOS. Apple Terminal can run the app, but it cannot display inline images.

1. Clone and build this fork:

```sh
git clone https://github.com/natekettles/reddix.git
cd reddix
cargo build --release
```

2. Open Reddit in Chrome while logged in.

3. Open Chrome DevTools:

```text
View -> Developer -> Developer Tools
```

4. Go to:

```text
Application -> Cookies -> https://www.reddit.com
```

## Install
5. Copy the cookie values named `reddit_session` and `token_v2`.

### GitHub Releases
6. Export them in your shell:

You can download the latest [release](https://github.com/ck-zhang/reddix/releases/latest) from GitHub
```sh
export REDDIT_SESSION='your_reddit_session_cookie_value_here'
export TOKEN_V2='your_token_v2_cookie_value_here'
```

### Use the install script:
7. Optionally persist them by adding those same two lines to `~/.zshrc` or `~/.bashrc`, then reload your shell:

```sh
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/ck-zhang/reddix/releases/latest/download/reddix-installer.sh | sh
source ~/.zshrc
```

### Install via Homebrew:
8. Test cookie auth without opening the TUI:

```sh
brew install reddix
cargo run --example cookie_probe
```

You should see output like:

```text
children=1
```

### Install via AUR (Archlinux):
From source:
9. Run Reddix:

```sh
yay -S reddix
cargo run --release
```
Binaries:

Or run the built binary directly:

```sh
yay -S reddix-bin
./target/release/reddix
```

## Quickstart
When `TOKEN_V2` is set, this fork automatically uses cookie auth and skips the OAuth setup flow. `REDDIT_SESSION` is optional for some reads, but setting both matches the browser session most reliably.

## Notes

- Cookie auth uses `https://www.reddit.com/` rather than the OAuth API host.
- Some Reddit responses may be rate limited. If the app shows a fetch error, wait a few minutes and retry.
- Inline image previews require a terminal that supports the Kitty graphics protocol, such as Ghostty or Kitty.
- Apple Terminal does not support Kitty graphics, so this fork disables those image escapes there.

1. Apply for a Reddit “script” via the [Reddit support form](https://support.reddithelp.com/hc/en-us/requests/new?ticket_form_id=14868593862164&tf_14867328473236=api_request_type_enterprise). Once approved, set the redirect URI to `http://127.0.0.1:65010/reddix/callback`.
2. Launch `reddix`, press `m`, and follow the guided menu for setup.
3. Prefer to configure things manually? Copy [`docs/examples/config.yaml`](docs/examples/config.yaml) into `~/.config/reddix/config.yaml` and fill in your credentials.
## Features

Note: As of Nov 2025, Reddit blocked the old `reddit.com/prefs/apps` flow. Apply via the [Reddit support form](https://support.reddithelp.com/hc/en-us/requests/new?ticket_form_id=14868593862164&tf_14867328473236=api_request_type_enterprise) (context: https://www.reddit.com/r/redditdev/comments/1oug31u/introducing_the_responsible_builder_policy_new/).
- Image previews based on the kitty graphics protocol
- Video playback via [mpv](https://mpv.io)'s Kitty integration
- Gallery browsing with inline navigation controls
- Multi-account support
- Keyboard-first navigation
- Smart caching
- NSFW filter toggle

Core shortcuts: `j/k` move, `h/l` change panes, `m` guided menu, `o` action menu, `r` refresh, `s` sync subs, `u/d` vote, `q` quit.

## Support
## Upstream OAuth Setup

The original Reddix OAuth flow is still present. If you want to use official OAuth instead of cookie auth, unset `TOKEN_V2` and follow the upstream setup approach:

1. Apply for a Reddit app via the [Reddit support form](https://support.reddithelp.com/hc/en-us/requests/new?ticket_form_id=14868593862164&tf_14867328473236=api_request_type_enterprise).
2. Once approved, set the redirect URI to `http://127.0.0.1:65010/reddix/callback`.
3. Launch `reddix`, press `m`, and follow the guided menu for setup.

- I welcome feature requests and contributions; the project is still in its early stages.
- Track ongoing ideas in the [feature request log](docs/feature-requests.md).
- Donations: [https://ko-fi.com/ckzhang](https://ko-fi.com/ckzhang)
As of Nov 2025, Reddit blocked the old `reddit.com/prefs/apps` flow. Apply via the Reddit support form instead.
3 changes: 3 additions & 0 deletions dist-workspace.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ installers = ["shell", "powershell"]
targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]
# Where to host releases
hosting = "github"
# This fork keeps a manual workflow_dispatch trigger and simpler tag glob so
# GitHub Actions can build release assets on demand.
allow-dirty = ["ci"]
9 changes: 9 additions & 0 deletions docs/release-notes.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
release:
- version: "0.2.10"
title: "What's new in v0.2.10"
banner: "Cookie auth for personal Reddit sessions."
summary: "This fork can use your browser Reddit cookies when OAuth app approval is unavailable or delayed."
url: "https://github.com/natekettles/reddix/releases/tag/v0.2.10"
details:
- "Set TOKEN_V2 and optional REDDIT_SESSION to use cookie auth instead of OAuth."
- "Run cargo run --example cookie_probe to check credentials before opening the TUI."
- "Apple Terminal now disables Kitty image escapes automatically."
- version: "0.2.9"
title: "What's new in v0.2.9"
banner: "Windows previews now scale correctly."
Expand Down
46 changes: 46 additions & 0 deletions examples/cookie_probe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use std::sync::Arc;

use anyhow::Result;
use reddix::reddit::{self, ListingOptions, SortOption, TokenProvider};

struct EnvTokenProvider {
access_token: String,
}

impl TokenProvider for EnvTokenProvider {
fn token(&self) -> Result<reddit::OAuthToken> {
Ok(reddit::OAuthToken {
access_token: self.access_token.clone(),
token_type: "bearer".to_string(),
expires_at: None,
})
}
}

fn main() -> Result<()> {
let reddit_session = std::env::var("REDDIT_SESSION")?;
let token_v2 = std::env::var("TOKEN_V2")?;
let cookie_header = format!("reddit_session={reddit_session}; token_v2={token_v2}");
let token_provider = Arc::new(EnvTokenProvider {
access_token: token_v2,
});
let client = reddit::Client::new(
token_provider,
reddit::ClientConfig {
user_agent: "reddix-cookie-probe/0.1".to_string(),
base_url: Some("https://www.reddit.com/".to_string()),
http_client: None,
cookie_header: Some(cookie_header),
bearer_auth: false,
},
)?;
let listing = client.front_page(
SortOption::Hot,
ListingOptions {
limit: Some(1),
..Default::default()
},
)?;
println!("children={}", listing.children.len());
Ok(())
}
73 changes: 72 additions & 1 deletion src/app.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::sync::Arc;
use std::time::SystemTime;

use anyhow::{Context, Result};

Expand All @@ -12,6 +13,20 @@ use crate::storage;
use crate::theme;
use crate::ui;

struct EnvTokenProvider {
access_token: String,
}

impl reddit::TokenProvider for EnvTokenProvider {
fn token(&self) -> Result<reddit::OAuthToken> {
Ok(reddit::OAuthToken {
access_token: self.access_token.clone(),
token_type: "bearer".to_string(),
expires_at: None::<SystemTime>,
})
}
}

pub fn run() -> Result<()> {
let cfg = config::load(config::LoadOptions::default()).context("load config")?;
let config_path = config::default_path();
Expand Down Expand Up @@ -65,11 +80,65 @@ pub fn run() -> Result<()> {
let mut session_manager: Option<Arc<session::Manager>> = None;
let mut fetch_subreddits_on_start = false;

let reddit_session = std::env::var("REDDIT_SESSION")
.ok()
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty());
let token_v2 = std::env::var("TOKEN_V2")
.ok()
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty());

let login_ready = !cfg.reddit.client_id.trim().is_empty()
&& !cfg.reddit.user_agent.trim().is_empty()
&& !cfg.reddit.redirect_uri.trim().is_empty();

if login_ready {
if let Some(token_v2) = token_v2 {
let user_agent = if cfg.reddit.user_agent.trim().is_empty() {
format!("reddix/{} cookie-auth", env!("CARGO_PKG_VERSION"))
} else {
cfg.reddit.user_agent.clone()
};
let mut cookie_parts = Vec::new();
if let Some(reddit_session) = reddit_session {
cookie_parts.push(format!("reddit_session={reddit_session}"));
}
cookie_parts.push(format!("token_v2={token_v2}"));

let token_provider: Arc<dyn reddit::TokenProvider> = Arc::new(EnvTokenProvider {
access_token: token_v2,
});
if let Ok(client) = reddit::Client::new(
token_provider,
reddit::ClientConfig {
user_agent,
base_url: Some("https://www.reddit.com/".to_string()),
http_client: None,
cookie_header: Some(cookie_parts.join("; ")),
bearer_auth: false,
},
) {
let client = Arc::new(client);
let subreddit_api: Arc<dyn SubredditService + Send + Sync> =
Arc::new(data::RedditSubredditService::new(client.clone()));
let feed_api: Arc<dyn FeedService + Send + Sync> =
Arc::new(data::RedditFeedService::new(client.clone()));
let comment_api: Arc<dyn CommentService + Send + Sync> =
Arc::new(data::RedditCommentService::new(client.clone()));
let interaction_api: Arc<dyn InteractionService + Send + Sync> =
Arc::new(data::RedditInteractionService::new(client.clone()));

feed_service = Some(feed_api);
subreddit_service = Some(subreddit_api);
comment_service = Some(comment_api);
interaction_service = Some(interaction_api);
fetch_subreddits_on_start = true;
posts.clear();
status = "Using Reddit cookie auth from TOKEN_V2/REDDIT_SESSION. Press q to quit."
.to_string();
content = "Cookie auth mode is active. Loading subscribed feeds...".to_string();
}
} else if login_ready {
let flow_cfg = auth::Config {
client_id: cfg.reddit.client_id.clone(),
client_secret: cfg.reddit.client_secret.clone(),
Expand Down Expand Up @@ -100,6 +169,8 @@ pub fn run() -> Result<()> {
user_agent: cfg.reddit.user_agent.clone(),
base_url: None,
http_client: None,
cookie_header: None,
bearer_auth: true,
},
) {
let client = Arc::new(client);
Expand Down
Loading