diff --git a/crates/tor-dirmgr/src/bootstrap.rs b/crates/tor-dirmgr/src/bootstrap.rs
index cbc810159760f60eadb561872b5ee0e68b120363..bf2fc98a1a11d50b0880df57c5aa3de2d0481177 100644
--- a/crates/tor-dirmgr/src/bootstrap.rs
+++ b/crates/tor-dirmgr/src/bootstrap.rs
@@ -9,6 +9,7 @@ use std::{
 };
 
 use crate::state::DirState;
+use crate::DirMgrConfig;
 use crate::{
     docid::{self, ClientRequest},
     upgrade_weak_ref, DirMgr, DocId, DocQuery, DocumentText, Error, Readiness, Result,
@@ -117,10 +118,11 @@ pub(crate) fn make_consensus_request(
     now: SystemTime,
     flavor: ConsensusFlavor,
     store: &dyn Store,
+    config: &DirMgrConfig,
 ) -> Result<ClientRequest> {
     let mut request = tor_dirclient::request::ConsensusRequest::new(flavor);
 
-    let default_cutoff = crate::default_consensus_cutoff(now)?;
+    let default_cutoff = crate::default_consensus_cutoff(now, &config.tolerance)?;
 
     match store.latest_consensus_meta(flavor) {
         Ok(Some(meta)) => {
@@ -147,6 +149,7 @@ pub(crate) fn make_requests_for_documents<R: Runtime>(
     rt: &R,
     docs: &[DocId],
     store: &dyn Store,
+    config: &DirMgrConfig,
 ) -> Result<Vec<ClientRequest>> {
     let mut res = Vec::new();
     for q in docid::partition_by_type(docs.iter().copied())
@@ -155,7 +158,12 @@ pub(crate) fn make_requests_for_documents<R: Runtime>(
     {
         match q {
             DocQuery::LatestConsensus { flavor, .. } => {
-                res.push(make_consensus_request(rt.wallclock(), flavor, store)?);
+                res.push(make_consensus_request(
+                    rt.wallclock(),
+                    flavor,
+                    store,
+                    config,
+                )?);
             }
             DocQuery::AuthCert(ids) => {
                 res.push(ClientRequest::AuthCert(ids.into_iter().collect()));
@@ -211,7 +219,12 @@ async fn fetch_multiple<R: Runtime>(
 ) -> Result<Vec<(ClientRequest, DirResponse)>> {
     let requests = {
         let store = dirmgr.store.lock().expect("store lock poisoned");
-        make_requests_for_documents(&dirmgr.runtime, missing, store.deref())?
+        make_requests_for_documents(
+            &dirmgr.runtime,
+            missing,
+            store.deref(),
+            &dirmgr.config.get(),
+        )?
     };
 
     #[cfg(test)]
diff --git a/crates/tor-dirmgr/src/lib.rs b/crates/tor-dirmgr/src/lib.rs
index 46cd75b43cd2a31396dcc9eeb648a76f16b9ebde..5d8d96de49d601e4fa93961295835c66897df525 100644
--- a/crates/tor-dirmgr/src/lib.rs
+++ b/crates/tor-dirmgr/src/lib.rs
@@ -942,15 +942,19 @@ fn upgrade_weak_ref<T>(weak: &Weak<T>) -> Result<Arc<T>> {
     Weak::upgrade(weak).ok_or(Error::ManagerDropped)
 }
 
-/// At most how much age can we tolerate in a consensus?
-///
-/// TODO: Make this public and/or use it elsewhere; see arti#412.
-const CONSENSUS_ALLOW_SKEW: Duration = Duration::from_secs(3600 * 48);
-
 /// Given a time `now`, return the age of the oldest consensus that we should
 /// request at that time.
-pub(crate) fn default_consensus_cutoff(now: SystemTime) -> Result<SystemTime> {
-    let cutoff = time::OffsetDateTime::from(now - CONSENSUS_ALLOW_SKEW);
+///
+/// DOCDOC allow_skew.
+pub(crate) fn default_consensus_cutoff(
+    now: SystemTime,
+    tolerance: &DirSkewTolerance,
+) -> Result<SystemTime> {
+    /// We _always_ allow at least this much age in our consensuses, to account
+    /// for the fact that consensuses have some lifetime.
+    const MIN_AGE_TO_ALLOW: Duration = Duration::from_secs(3 * 3600);
+    let allow_skew = std::cmp::max(MIN_AGE_TO_ALLOW, tolerance.post_valid_tolerance);
+    let cutoff = time::OffsetDateTime::from(now - allow_skew);
     // We now round cutoff to the next hour, so that we aren't leaking our exact
     // time to the directory cache.
     //
@@ -1122,19 +1126,26 @@ mod test {
             let later = tomorrow + Duration::from_secs(86400);
 
             let (_tempdir, mgr) = new_mgr(rt);
+            let config = DirMgrConfig::default();
 
             // Try with an empty store.
             let req = {
                 let store = mgr.store.lock().unwrap();
-                bootstrap::make_consensus_request(now, ConsensusFlavor::Microdesc, store.deref())
-                    .unwrap()
+                bootstrap::make_consensus_request(
+                    now,
+                    ConsensusFlavor::Microdesc,
+                    store.deref(),
+                    &config,
+                )
+                .unwrap()
             };
+            let tolerance = DirSkewTolerance::default().post_valid_tolerance;
             match req {
                 ClientRequest::Consensus(r) => {
                     assert_eq!(r.old_consensus_digests().count(), 0);
                     let date = r.last_consensus_date().unwrap();
-                    assert!(date >= now - CONSENSUS_ALLOW_SKEW);
-                    assert!(date <= now - CONSENSUS_ALLOW_SKEW + Duration::from_secs(3600));
+                    assert!(date >= now - tolerance);
+                    assert!(date <= now - tolerance + Duration::from_secs(3600));
                 }
                 _ => panic!("Wrong request type"),
             }
@@ -1157,8 +1168,13 @@ mod test {
             // Now try again.
             let req = {
                 let store = mgr.store.lock().unwrap();
-                bootstrap::make_consensus_request(now, ConsensusFlavor::Microdesc, store.deref())
-                    .unwrap()
+                bootstrap::make_consensus_request(
+                    now,
+                    ConsensusFlavor::Microdesc,
+                    store.deref(),
+                    &config,
+                )
+                .unwrap()
             };
             match req {
                 ClientRequest::Consensus(r) => {
@@ -1186,13 +1202,18 @@ mod test {
             #[cfg(feature = "routerdesc")]
             let rd_ids: Vec<DocId> = (0..1000).map(|_| DocId::RouterDesc(rng.gen())).collect();
             let md_ids: Vec<DocId> = (0..1000).map(|_| DocId::Microdesc(rng.gen())).collect();
+            let config = DirMgrConfig::default();
 
             // Try an authcert.
             let query = DocId::AuthCert(certid1);
             let store = mgr.store.lock().unwrap();
-            let reqs =
-                bootstrap::make_requests_for_documents(&mgr.runtime, &[query], store.deref())
-                    .unwrap();
+            let reqs = bootstrap::make_requests_for_documents(
+                &mgr.runtime,
+                &[query],
+                store.deref(),
+                &config,
+            )
+            .unwrap();
             assert_eq!(reqs.len(), 1);
             let req = &reqs[0];
             if let ClientRequest::AuthCert(r) = req {
@@ -1202,17 +1223,26 @@ mod test {
             }
 
             // Try a bunch of mds.
-            let reqs = bootstrap::make_requests_for_documents(&mgr.runtime, &md_ids, store.deref())
-                .unwrap();
+            let reqs = bootstrap::make_requests_for_documents(
+                &mgr.runtime,
+                &md_ids,
+                store.deref(),
+                &config,
+            )
+            .unwrap();
             assert_eq!(reqs.len(), 2);
             assert!(matches!(reqs[0], ClientRequest::Microdescs(_)));
 
             // Try a bunch of rds.
             #[cfg(feature = "routerdesc")]
             {
-                let reqs =
-                    bootstrap::make_requests_for_documents(&mgr.runtime, &rd_ids, store.deref())
-                        .unwrap();
+                let reqs = bootstrap::make_requests_for_documents(
+                    &mgr.runtime,
+                    &rd_ids,
+                    store.deref(),
+                    &config,
+                )
+                .unwrap();
                 assert_eq!(reqs.len(), 2);
                 assert!(matches!(reqs[0], ClientRequest::RouterDescs(_)));
             }
@@ -1224,6 +1254,7 @@ mod test {
         tor_rtcompat::test_with_one_runtime!(|rt| async {
             let now = rt.wallclock();
             let day = Duration::from_secs(86400);
+            let config = DirMgrConfig::default();
 
             let (_tempdir, mgr) = new_mgr(rt);
 
@@ -1231,7 +1262,8 @@ mod test {
             let q = DocId::Microdesc([99; 32]);
             let r = {
                 let store = mgr.store.lock().unwrap();
-                bootstrap::make_requests_for_documents(&mgr.runtime, &[q], store.deref()).unwrap()
+                bootstrap::make_requests_for_documents(&mgr.runtime, &[q], store.deref(), &config)
+                    .unwrap()
             };
             let expanded = mgr.expand_response_text(&r[0], "ABC".to_string());
             assert_eq!(&expanded.unwrap(), "ABC");
@@ -1244,8 +1276,13 @@ mod test {
             };
             let r = {
                 let store = mgr.store.lock().unwrap();
-                bootstrap::make_requests_for_documents(&mgr.runtime, &[latest_id], store.deref())
-                    .unwrap()
+                bootstrap::make_requests_for_documents(
+                    &mgr.runtime,
+                    &[latest_id],
+                    store.deref(),
+                    &config,
+                )
+                .unwrap()
             };
             let expanded = mgr.expand_response_text(&r[0], "DEF".to_string());
             assert_eq!(&expanded.unwrap(), "DEF");
@@ -1274,8 +1311,13 @@ mod test {
             // one.
             let r = {
                 let store = mgr.store.lock().unwrap();
-                bootstrap::make_requests_for_documents(&mgr.runtime, &[latest_id], store.deref())
-                    .unwrap()
+                bootstrap::make_requests_for_documents(
+                    &mgr.runtime,
+                    &[latest_id],
+                    store.deref(),
+                    &config,
+                )
+                .unwrap()
             };
             let expanded = mgr.expand_response_text(&r[0], "hello".to_string());
             assert_eq!(&expanded.unwrap(), "hello");