1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! `loopauth` acquires OAuth 2.0 provider tokens for CLI applications via the
//! Authorization Code + PKCE flow ([RFC 6749], [RFC 7636]). It is **provider token
//! acquisition only**, rather than app authentication or session management.
//!
//! [RFC 6749]: https://datatracker.ietf.org/doc/html/rfc6749
//! [RFC 7636]: https://datatracker.ietf.org/doc/html/rfc7636
//!
//! Given a `client_id`, `auth_url`, and `token_url`, [`CliTokenClient`] opens the
//! user's browser to the authorization URL, spins up a short-lived loopback
//! server to receive the redirect callback, exchanges the authorization code for
//! tokens, and returns a [`TokenSet`] to the caller.
//!
//! The callback server runs over plain HTTP by default. For providers that
//! require HTTPS redirect URIs (e.g. Slack), call
//! [`.use_https_with()`](CliTokenClientBuilder::use_https_with) with a
//! [`TlsCertificate`] to serve over TLS instead. See the
//! [HTTPS callbacks](#https-callbacks) section below.
//!
//! Token storage and downstream identity consumption are intentionally out of
//! scope; use the [`TokenStore`] trait to provide your own persistence.
//!
//! # Two-Layer Pattern
//!
//! `loopauth` returns provider tokens only. Your backend handles app identity:
//!
//! 1. Call [`CliTokenClient::run_authorization_flow`] → provider returns a [`TokenSet`]
//! 2. Send [`TokenSet::id_token_raw`] to your backend → validate and issue your own session token
//!
//! # Quick start
//!
//! With explicit URLs:
//!
//! ```no_run
//! use loopauth::{CliTokenClient, RequestScope};
//!
//! # async fn run() -> Result<(), Box<dyn std::error::Error>> {
//! let client = CliTokenClient::builder()
//! .client_id("my-client-id")
//! .auth_url(url::Url::parse("https://provider.example.com/authorize")?)
//! .token_url(url::Url::parse("https://provider.example.com/token")?)
//! .with_openid_scope()
//! .add_scopes([RequestScope::Email])
//! .without_jwks_validation() // or .jwks_validator(Box::new(my_validator))
//! .build();
//!
//! // let tokens = client.run_authorization_flow().await?;
//! # Ok(())
//! # }
//! ```
//!
//! With OIDC auto-discovery (provider URLs are fetched automatically):
//!
//! ```no_run
//! use loopauth::{CliTokenClientBuilder, RequestScope, oidc::OpenIdConfiguration};
//! use url::Url;
//!
//! # async fn run() -> Result<(), Box<dyn std::error::Error>> {
//! let open_id_configuration = OpenIdConfiguration::fetch(
//! Url::parse("https://provider.example.com")?,
//! ).await?;
//!
//! let client = CliTokenClientBuilder::from_open_id_configuration(&open_id_configuration)
//! .client_id("my-client-id")
//! .with_open_id_configuration_jwks_validator(&open_id_configuration)
//! .add_scopes([RequestScope::Email])
//! .build();
//!
//! // let tokens = client.run_authorization_flow().await?;
//! # Ok(())
//! # }
//! ```
//!
//! # HTTPS callbacks
//!
//! Some providers require `https://` redirect URIs, even for localhost.
//! [`TlsCertificate::ensure_localhost`] handles certificate generation via
//! [`mkcert`](https://github.com/FiloSottile/mkcert) automatically:
//!
//! ```no_run
//! use loopauth::{CliTokenClient, TlsCertificate};
//! use std::path::PathBuf;
//!
//! # async fn run() -> Result<(), Box<dyn std::error::Error>> {
//! // First run: generates certs via mkcert. Later runs: loads existing.
//! let tls_dir = PathBuf::from("/home/user/.config/my-cli/tls");
//! let cert = TlsCertificate::ensure_localhost(&tls_dir)?;
//!
//! let client = CliTokenClient::builder()
//! .client_id("my-client-id")
//! .auth_url(url::Url::parse("https://provider.example.com/authorize")?)
//! .token_url(url::Url::parse("https://provider.example.com/token")?)
//! .use_https_with(cert)
//! .build();
//!
//! // let tokens = client.run_authorization_flow().await?;
//! # Ok(())
//! # }
//! ```
//!
//! End users need `mkcert` installed and its CA trusted (`mkcert -install`,
//! one-time). See [`TlsCertificate::SETUP_GUIDE_MANAGED`] for end-user
//! instructions tailored to this workflow, or [`TlsCertificate::SETUP_GUIDE`]
//! for the full manual guide.
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use TokenStore;
pub use ;
pub use ;