diff --git a/goatherd.go b/goatherd.go
index be9c2f12165822b24b4d9a095efefdb662d4fc6a..cc22b233248ff17813991feb13330a4346d34ed7 100644
--- a/goatherd.go
+++ b/goatherd.go
@@ -19,6 +19,8 @@ import (
     "github.com/mattn/go-sqlite3"
 )
 
+const otpLen = 8
+
 // wrapper because time.Duration doesn't implement UnmarshalJSON
 type duration struct {
     time.Duration
@@ -174,7 +176,7 @@ func get_otp(db db_conn, name string) (*hotp.HOTP, error) {
     secret, count, err := get_user(db, name)
     if err != nil { return nil, err }
 
-    return hotp.NewHOTP(secret, count, 6), nil
+    return hotp.NewHOTP(secret, count, otpLen), nil
 }
 
 func transaction_failed(err error) bool {
diff --git a/goatherd_test.go b/goatherd_test.go
index 60627c2b3790864526a389773e9630e5b243d9bf..c1ddc74d0a4d8fdc05981f0b5f70f36d5287e101 100644
--- a/goatherd_test.go
+++ b/goatherd_test.go
@@ -115,14 +115,14 @@ func check_offer_t(t *testing.T) {
         if ok { t.Fail() }
 
         t.Run("too_far_out", func(t *testing.T) {
-            ahead := hotp.NewHOTP(secret, count + cfg.Lookahead + 1, 6)
+            ahead := hotp.NewHOTP(secret, count + cfg.Lookahead + 1, otpLen)
             ok, err = check_offer(db, "mock", username, ahead.OTP())
             if ok { t.Fail() }
         })
     })
 
     t.Run("ok", func(t *testing.T) {
-        cur := hotp.NewHOTP(secret, count, 6)
+        cur := hotp.NewHOTP(secret, count, otpLen)
         ok, err := check_offer(db, "mock", username, cur.OTP())
         t_err_fatal(t, err)
         if !ok { t.Fail() }
@@ -136,7 +136,7 @@ func check_offer_t(t *testing.T) {
 
         t.Run("lookahead", func(t *testing.T) {
             ok, err := check_offer(db, "mock", username,
-                hotp.NewHOTP(secret, cur.Counter() + cfg.Lookahead, 6).OTP())
+                hotp.NewHOTP(secret, cur.Counter() + cfg.Lookahead, otpLen).OTP())
             t_err_fatal(t, err)
             if !ok { t.Fail() }
         })