diff --git a/aleksis/apps/kort/migrations/0017_cardprinter_oauth2_client_secret.py b/aleksis/apps/kort/migrations/0016_cardprinter_oauth2_client_secret.py
similarity index 81%
rename from aleksis/apps/kort/migrations/0017_cardprinter_oauth2_client_secret.py
rename to aleksis/apps/kort/migrations/0016_cardprinter_oauth2_client_secret.py
index ca460fe86703a49b14765a609f3500eded91c36a..4e022e0596ee57df0abbd290a3601d23b7c7e7f7 100644
--- a/aleksis/apps/kort/migrations/0017_cardprinter_oauth2_client_secret.py
+++ b/aleksis/apps/kort/migrations/0016_cardprinter_oauth2_client_secret.py
@@ -1,4 +1,4 @@
-# Generated by Django 4.1.9 on 2023-06-17 18:42
+# Generated by Django 4.2.4 on 2023-08-30 14:25
 
 from django.db import migrations, models
 import django.db.models.deletion
@@ -8,7 +8,7 @@ class Migration(migrations.Migration):
 
     dependencies = [
         ("sites", "0002_alter_domain_unique"),
-        ("kort", "0016_card_last_read_counter"),
+        ("kort", "0015_migrate_scopes"),
     ]
 
     operations = [
diff --git a/aleksis/apps/kort/models.py b/aleksis/apps/kort/models.py
index e84e2dc36c9a0c6157652d91e81c56dc9ab2facf..ad4a435657a595b6022c81cfd3634bcc81141417 100644
--- a/aleksis/apps/kort/models.py
+++ b/aleksis/apps/kort/models.py
@@ -14,6 +14,7 @@ from django.utils.translation import gettext as _
 
 from celery.result import AsyncResult
 from model_utils.models import TimeStampedModel
+from oauth2_provider.generators import generate_client_secret
 
 from aleksis.core.mixins import ExtensibleModel
 from aleksis.core.models import OAuthApplication, Person
@@ -82,27 +83,41 @@ class CardPrinter(ExtensibleModel):
         null=True,
         related_name="card_printers",
     )
+    oauth2_client_secret = models.CharField(
+        max_length=255,
+        blank=True,
+        verbose_name=_("OAuth2 client secret"),
+    )
 
     # Settings
-    cups_printer = models.CharField(max_length=255, verbose_name=_("CUPS printer"), blank=True)
+    cups_printer = models.CharField(
+        max_length=255,
+        verbose_name=_("CUPS printer"),
+        blank=True,
+        help_text=_("Leave blank to deactivate CUPS printing"),
+    )
     generate_number_on_server = models.BooleanField(
         default=True, verbose_name=_("Generate card number on server")
     )
     card_detector = models.CharField(max_length=255, verbose_name=_("Card detector"), blank=True)
 
     def save(self, *args, **kwargs):
+        super().save(*args, **kwargs)
+
         if not self.oauth2_application:
+            client_secret = generate_client_secret()
             application = OAuthApplication(
                 client_type=OAuthApplication.CLIENT_CONFIDENTIAL,
                 authorization_grant_type=OAuthApplication.GRANT_CLIENT_CREDENTIALS,
                 name=f"Card printer: {self.name}",
-                redirect_uris="urn:ietf:wg:oauth:2.0:oob",
                 allowed_scopes=[self.scope],
+                client_secret=client_secret,
             )
             application.save()
             self.oauth2_application = application
+            self.oauth2_client_secret = client_secret
 
-        super().save(*args, **kwargs)
+            super().save(*args, **kwargs)
 
     def __str__(self):
         return self.name
@@ -127,7 +142,7 @@ class CardPrinter(ExtensibleModel):
         config = {
             "base_url": settings.BASE_URL,
             "client_id": self.oauth2_application.client_id,
-            "client_secret": self.oauth2_application.client_secret,
+            "client_secret": self.oauth2_client_secret,
         }
         return config