diff --git a/authentik/core/templates/generic/autosubmit_form_full.html b/authentik/core/templates/generic/autosubmit_form_full.html
deleted file mode 100644
index e3b044b8a..000000000
--- a/authentik/core/templates/generic/autosubmit_form_full.html
+++ /dev/null
@@ -1,34 +0,0 @@
-{% extends "login/base_full.html" %}
-
-{% load authentik_utils %}
-{% load i18n %}
-
-{% block title %}
-{{ title }}
-{% endblock %}
-
-{% block card %}
-<form method="POST" action="{{ url }}" autosubmit>
-    {% csrf_token %}
-    {% for key, value in attrs.items %}
-    <input type="hidden" name="{{ key }}" value="{{ value }}">
-    {% endfor %}
-    <div class="pf-c-form__group pf-u-display-flex pf-u-justify-content-center">
-        <div class="pf-c-form__group-control">
-            <span class="pf-c-spinner" role="progressbar" aria-valuetext="Loading...">
-                <span class="pf-c-spinner__clipper"></span>
-                <span class="pf-c-spinner__lead-ball"></span>
-                <span class="pf-c-spinner__tail-ball"></span>
-            </span>
-        </div>
-    </div>
-    <div class="pf-c-form__group pf-m-action">
-        <div class="pf-c-form__actions">
-            <button class="pf-c-button pf-m-primary pf-m-block" type="submit">{% trans 'Continue' %}</button>
-        </div>
-    </div>
-</form>
-<script>
-document.querySelector("form").submit();
-</script>
-{% endblock %}
diff --git a/authentik/core/types.py b/authentik/core/types.py
index 1f9ff8223..0f93a1589 100644
--- a/authentik/core/types.py
+++ b/authentik/core/types.py
@@ -26,7 +26,7 @@ class UILoginButtonSerializer(Serializer):
 
     name = CharField()
     url = CharField()
-    icon_url = CharField()
+    icon_url = CharField(required=False)
 
     def create(self, validated_data: dict) -> Model:
         return Model()
diff --git a/authentik/flows/models.py b/authentik/flows/models.py
index 5de7369d1..d36cbb2e2 100644
--- a/authentik/flows/models.py
+++ b/authentik/flows/models.py
@@ -77,7 +77,7 @@ class Stage(SerializerModel):
 
 
 def in_memory_stage(view: Type["StageView"]) -> Stage:
-    """Creates an in-memory stage instance, based on a `_type` as view."""
+    """Creates an in-memory stage instance, based on a `view` as view."""
     stage = Stage()
     # Because we can't pickle a locally generated function,
     # we set the view as a separate property and reference a generic function
diff --git a/authentik/providers/saml/tests/test_auth_n_request.py b/authentik/providers/saml/tests/test_auth_n_request.py
index e01c45c56..f85f05809 100644
--- a/authentik/providers/saml/tests/test_auth_n_request.py
+++ b/authentik/providers/saml/tests/test_auth_n_request.py
@@ -81,6 +81,9 @@ class TestAuthNRequest(TestCase):
         self.source = SAMLSource.objects.create(
             slug="provider",
             issuer="authentik",
+            pre_authentication_flow=Flow.objects.get(
+                slug="default-source-pre-authentication"
+            ),
             signing_kp=cert,
         )
         self.factory = RequestFactory()
diff --git a/authentik/providers/saml/tests/test_schema.py b/authentik/providers/saml/tests/test_schema.py
index c09a112b8..bb0cbed23 100644
--- a/authentik/providers/saml/tests/test_schema.py
+++ b/authentik/providers/saml/tests/test_schema.py
@@ -37,6 +37,9 @@ class TestSchema(TestCase):
             slug="provider",
             issuer="authentik",
             signing_kp=cert,
+            pre_authentication_flow=Flow.objects.get(
+                slug="default-source-pre-authentication"
+            ),
         )
         self.factory = RequestFactory()
 
diff --git a/authentik/sources/saml/api.py b/authentik/sources/saml/api.py
index d499ce20b..c6ca57bd1 100644
--- a/authentik/sources/saml/api.py
+++ b/authentik/sources/saml/api.py
@@ -18,6 +18,7 @@ class SAMLSourceSerializer(SourceSerializer):
 
         model = SAMLSource
         fields = SourceSerializer.Meta.fields + [
+            "pre_authentication_flow",
             "issuer",
             "sso_url",
             "slo_url",
diff --git a/authentik/sources/saml/forms.py b/authentik/sources/saml/forms.py
index 66801ec27..8afe9c822 100644
--- a/authentik/sources/saml/forms.py
+++ b/authentik/sources/saml/forms.py
@@ -14,6 +14,9 @@ class SAMLSourceForm(forms.ModelForm):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
 
+        self.fields["pre_authentication_flow"].queryset = Flow.objects.filter(
+            designation=FlowDesignation.AUTHENTICATION
+        )
         self.fields["authentication_flow"].queryset = Flow.objects.filter(
             designation=FlowDesignation.AUTHENTICATION
         )
@@ -32,6 +35,7 @@ class SAMLSourceForm(forms.ModelForm):
             "name",
             "slug",
             "enabled",
+            "pre_authentication_flow",
             "authentication_flow",
             "enrollment_flow",
             "issuer",
diff --git a/authentik/sources/saml/migrations/0010_samlsource_pre_authentication_flow.py b/authentik/sources/saml/migrations/0010_samlsource_pre_authentication_flow.py
new file mode 100644
index 000000000..e153fabb8
--- /dev/null
+++ b/authentik/sources/saml/migrations/0010_samlsource_pre_authentication_flow.py
@@ -0,0 +1,53 @@
+# Generated by Django 3.1.7 on 2021-03-23 22:09
+
+import django.db.models.deletion
+from django.apps.registry import Apps
+from django.db import migrations, models
+from django.db.backends.base.schema import BaseDatabaseSchemaEditor
+
+from authentik.flows.models import FlowDesignation
+
+
+def create_default_pre_authentication_flow(
+    apps: Apps, schema_editor: BaseDatabaseSchemaEditor
+):
+    Flow = apps.get_model("authentik_flows", "Flow")
+    SAMLSource = apps.get_model("authentik_sources_saml", "samlsource")
+
+    db_alias = schema_editor.connection.alias
+
+    # Empty flow for providers where consent is implicitly given
+    flow, _ = Flow.objects.using(db_alias).update_or_create(
+        slug="default-source-pre-authentication",
+        designation=FlowDesignation.AUTHENTICATION,
+        defaults={"name": "Pre-Authentication", "title": ""},
+    )
+
+    for source in SAMLSource.objects.using(db_alias).all():
+        source.pre_authentication_flow = flow
+        source.save()
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("authentik_flows", "0016_auto_20201202_1307"),
+        ("authentik_sources_saml", "0009_auto_20210301_0949"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="samlsource",
+            name="pre_authentication_flow",
+            field=models.ForeignKey(
+                default=None,
+                null=True,
+                help_text="Flow used before authentication.",
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="source_pre_authentication",
+                to="authentik_flows.flow",
+            ),
+            preserve_default=False,
+        ),
+        migrations.RunPython(create_default_pre_authentication_flow),
+    ]
diff --git a/authentik/sources/saml/migrations/0011_auto_20210324_0736.py b/authentik/sources/saml/migrations/0011_auto_20210324_0736.py
new file mode 100644
index 000000000..f2470b57f
--- /dev/null
+++ b/authentik/sources/saml/migrations/0011_auto_20210324_0736.py
@@ -0,0 +1,25 @@
+# Generated by Django 3.1.7 on 2021-03-24 07:36
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("authentik_flows", "0016_auto_20201202_1307"),
+        ("authentik_sources_saml", "0010_samlsource_pre_authentication_flow"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="samlsource",
+            name="pre_authentication_flow",
+            field=models.ForeignKey(
+                help_text="Flow used before authentication.",
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="source_pre_authentication",
+                to="authentik_flows.flow",
+            ),
+        ),
+    ]
diff --git a/authentik/sources/saml/models.py b/authentik/sources/saml/models.py
index baebb9336..aba16f81d 100644
--- a/authentik/sources/saml/models.py
+++ b/authentik/sources/saml/models.py
@@ -11,6 +11,7 @@ from rest_framework.serializers import Serializer
 from authentik.core.models import Source
 from authentik.core.types import UILoginButton
 from authentik.crypto.models import CertificateKeyPair
+from authentik.flows.models import Flow
 from authentik.lib.utils.time import timedelta_string_validator
 from authentik.sources.saml.processors.constants import (
     DSA_SHA1,
@@ -51,6 +52,13 @@ class SAMLNameIDPolicy(models.TextChoices):
 class SAMLSource(Source):
     """Authenticate using an external SAML Identity Provider."""
 
+    pre_authentication_flow = models.ForeignKey(
+        Flow,
+        on_delete=models.CASCADE,
+        help_text=_("Flow used before authentication."),
+        related_name="source_pre_authentication",
+    )
+
     issuer = models.TextField(
         blank=True,
         default=None,
diff --git a/authentik/sources/saml/templates/saml/sp/login.html b/authentik/sources/saml/templates/saml/sp/login.html
deleted file mode 100644
index 5cf5c0502..000000000
--- a/authentik/sources/saml/templates/saml/sp/login.html
+++ /dev/null
@@ -1,26 +0,0 @@
-{% extends "login/base_full.html" %}
-
-{% load authentik_utils %}
-{% load i18n %}
-
-{% block title %}
-{% trans 'Authorize Application' %}
-{% endblock %}
-
-{% block card %}
-<form class="pf-c-form" method="POST" action="{{ request_url }}">
-    {% csrf_token %}
-    <input type="hidden" name="SAMLRequest" value="{{ request }}" />
-    <input type="hidden" name="RelayState" value="{{ relay_state }}" />
-    <div class="login-group">
-        <h3>
-            {% blocktrans with source=source.name %}
-            You're about to sign-in via {{ source }}.
-            {% endblocktrans %}
-        </h3>
-    </div>
-    <div class="pf-c-form__group pf-m-action">
-        <button class="pf-c-button pf-m-primary pf-m-block" type="submit">{% trans "Continue" %}</button>
-    </div>
-</form>
-{% endblock %}
diff --git a/authentik/sources/saml/tests/test_metadata.py b/authentik/sources/saml/tests/test_metadata.py
index 105b03476..6a65ee4ed 100644
--- a/authentik/sources/saml/tests/test_metadata.py
+++ b/authentik/sources/saml/tests/test_metadata.py
@@ -4,6 +4,7 @@ from django.test import RequestFactory, TestCase
 from lxml import etree  # nosec
 
 from authentik.crypto.models import CertificateKeyPair
+from authentik.flows.models import Flow
 from authentik.sources.saml.models import SAMLSource
 from authentik.sources.saml.processors.metadata import MetadataProcessor
 
@@ -20,6 +21,9 @@ class TestMetadataProcessor(TestCase):
             slug="provider",
             issuer="authentik",
             signing_kp=CertificateKeyPair.objects.first(),
+            pre_authentication_flow=Flow.objects.get(
+                slug="default-source-pre-authentication"
+            ),
         )
         request = self.factory.get("/")
         xml = MetadataProcessor(source, request).build_entity_descriptor()
diff --git a/authentik/sources/saml/views.py b/authentik/sources/saml/views.py
index c5618e7e5..8a60b6828 100644
--- a/authentik/sources/saml/views.py
+++ b/authentik/sources/saml/views.py
@@ -2,7 +2,8 @@
 from django.contrib.auth import logout
 from django.contrib.auth.mixins import LoginRequiredMixin
 from django.http import Http404, HttpRequest, HttpResponse
-from django.shortcuts import get_object_or_404, redirect, render
+from django.http.response import HttpResponseBadRequest
+from django.shortcuts import get_object_or_404, redirect
 from django.utils.decorators import method_decorator
 from django.utils.http import urlencode
 from django.utils.translation import gettext_lazy as _
@@ -10,8 +11,20 @@ from django.views import View
 from django.views.decorators.csrf import csrf_exempt
 from xmlsec import VerificationError
 
+from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
+from authentik.flows.models import in_memory_stage
+from authentik.flows.planner import (
+    PLAN_CONTEXT_REDIRECT,
+    PLAN_CONTEXT_SOURCE,
+    PLAN_CONTEXT_SSO,
+    FlowPlanner,
+)
+from authentik.flows.stage import ChallengeStageView
+from authentik.flows.views import NEXT_ARG_NAME, SESSION_KEY_GET, SESSION_KEY_PLAN
+from authentik.lib.utils.urls import redirect_with_qs
 from authentik.lib.views import bad_request_message
 from authentik.providers.saml.utils.encoding import nice64
+from authentik.providers.saml.views.flows import AutosubmitChallenge
 from authentik.sources.saml.exceptions import (
     MissingSAMLResponse,
     UnsupportedNameIDFormat,
@@ -20,11 +33,68 @@ from authentik.sources.saml.models import SAMLBindingTypes, SAMLSource
 from authentik.sources.saml.processors.metadata import MetadataProcessor
 from authentik.sources.saml.processors.request import RequestProcessor
 from authentik.sources.saml.processors.response import ResponseProcessor
+from authentik.stages.consent.stage import (
+    PLAN_CONTEXT_CONSENT_HEADER,
+    PLAN_CONTEXT_CONSENT_TITLE,
+    ConsentStageView,
+)
+
+PLAN_CONTEXT_TITLE = "title"
+PLAN_CONTEXT_URL = "url"
+PLAN_CONTEXT_ATTRS = "attrs"
+
+
+class AutosubmitStageView(ChallengeStageView):
+    """Wrapper stage to create an autosubmit challenge from plan context variables"""
+
+    def get_challenge(self, *args, **kwargs) -> Challenge:
+        return AutosubmitChallenge(
+            data={
+                "type": ChallengeTypes.native.value,
+                "component": "ak-stage-autosubmit",
+                "title": self.executor.plan.context.get(PLAN_CONTEXT_TITLE, ""),
+                "url": self.executor.plan.context.get(PLAN_CONTEXT_URL, ""),
+                "attrs": self.executor.plan.context.get(PLAN_CONTEXT_ATTRS, ""),
+            },
+        )
+
+    # Since `ak-stage-autosubmit` redirects off site, we don't have anything to check
+    def challenge_valid(self, response: ChallengeResponse) -> HttpResponse:
+        return HttpResponseBadRequest()
 
 
 class InitiateView(View):
     """Get the Form with SAML Request, which sends us to the IDP"""
 
+    def handle_login_flow(
+        self, source: SAMLSource, *stages_to_append, **kwargs
+    ) -> HttpResponse:
+        """Prepare Authentication Plan, redirect user FlowExecutor"""
+        # Ensure redirect is carried through when user was trying to
+        # authorize application
+        final_redirect = self.request.session.get(SESSION_KEY_GET, {}).get(
+            NEXT_ARG_NAME, "authentik_core:if-admin"
+        )
+        kwargs.update(
+            {
+                PLAN_CONTEXT_SSO: True,
+                PLAN_CONTEXT_SOURCE: source,
+                PLAN_CONTEXT_REDIRECT: final_redirect,
+            }
+        )
+        # We run the Flow planner here so we can pass the Pending user in the context
+        planner = FlowPlanner(source.pre_authentication_flow)
+        planner.allow_empty_flows = True
+        plan = planner.plan(self.request, kwargs)
+        for stage in stages_to_append:
+            plan.append(stage)
+        self.request.session[SESSION_KEY_PLAN] = plan
+        return redirect_with_qs(
+            "authentik_core:if-flow",
+            self.request.GET,
+            flow_slug=source.pre_authentication_flow.slug,
+        )
+
     def get(self, request: HttpRequest, source_slug: str) -> HttpResponse:
         """Replies with an XHTML SSO Request."""
         source: SAMLSource = get_object_or_404(SAMLSource, slug=source_slug)
@@ -38,29 +108,29 @@ class InitiateView(View):
             return redirect(f"{source.sso_url}?{url_args}")
         # As POST Binding we show a form
         saml_request = nice64(auth_n_req.build_auth_n())
+        injected_stages = []
+        plan_kwargs = {
+            PLAN_CONTEXT_TITLE: _("Redirecting to %(app)s..." % {"app": source.name}),
+            PLAN_CONTEXT_CONSENT_TITLE: _(
+                "Redirecting to %(app)s..." % {"app": source.name}
+            ),
+            PLAN_CONTEXT_ATTRS: {
+                "SAMLRequest": saml_request,
+                "RelayState": relay_state,
+            },
+            PLAN_CONTEXT_URL: source.sso_url,
+        }
+        # For just POST we add a consent stage,
+        # otherwise we default to POST_AUTO, with direct redirect
         if source.binding_type == SAMLBindingTypes.POST:
-            return render(
-                request,
-                "saml/sp/login.html",
-                {
-                    "request_url": source.sso_url,
-                    "request": saml_request,
-                    "relay_state": relay_state,
-                    "source": source,
-                },
-            )
-        # Or an auto-submit form
-        if source.binding_type == SAMLBindingTypes.POST_AUTO:
-            return render(
-                request,
-                "generic/autosubmit_form_full.html",
-                {
-                    "title": _("Redirecting to %(app)s..." % {"app": source.name}),
-                    "attrs": {"SAMLRequest": saml_request, "RelayState": relay_state},
-                    "url": source.sso_url,
-                },
-            )
-        raise Http404
+            injected_stages.append(in_memory_stage(ConsentStageView))
+            plan_kwargs[PLAN_CONTEXT_CONSENT_HEADER] = f"Continue to {source.name}"
+        injected_stages.append(in_memory_stage(AutosubmitStageView))
+        return self.handle_login_flow(
+            source,
+            *injected_stages,
+            **plan_kwargs,
+        )
 
 
 @method_decorator(csrf_exempt, name="dispatch")
diff --git a/authentik/stages/consent/stage.py b/authentik/stages/consent/stage.py
index c7d72ae31..387ea0783 100644
--- a/authentik/stages/consent/stage.py
+++ b/authentik/stages/consent/stage.py
@@ -15,6 +15,7 @@ from authentik.flows.stage import ChallengeStageView
 from authentik.lib.utils.time import timedelta_from_string
 from authentik.stages.consent.models import ConsentMode, ConsentStage, UserConsent
 
+PLAN_CONTEXT_CONSENT_TITLE = "consent_title"
 PLAN_CONTEXT_CONSENT_HEADER = "consent_header"
 PLAN_CONTEXT_CONSENT_PERMISSIONS = "consent_permissions"
 
@@ -42,6 +43,10 @@ class ConsentStageView(ChallengeStageView):
                 "component": "ak-stage-consent",
             }
         )
+        if PLAN_CONTEXT_CONSENT_TITLE in self.executor.plan.context:
+            challenge.initial_data["title"] = self.executor.plan.context[
+                PLAN_CONTEXT_CONSENT_TITLE
+            ]
         if PLAN_CONTEXT_CONSENT_HEADER in self.executor.plan.context:
             challenge.initial_data["header_text"] = self.executor.plan.context[
                 PLAN_CONTEXT_CONSENT_HEADER
@@ -50,16 +55,15 @@ class ConsentStageView(ChallengeStageView):
             challenge.initial_data["permissions"] = self.executor.plan.context[
                 PLAN_CONTEXT_CONSENT_PERMISSIONS
             ]
-        # If there's a pending user, update the `username` field
-        # this field is only used by password managers.
-        # If there's no user set, an error is raised later.
-        if user := self.get_pending_user():
-            challenge.initial_data["pending_user"] = user.username
-            challenge.initial_data["pending_user_avatar"] = user.avatar
         return challenge
 
     def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
         current_stage: ConsentStage = self.executor.current_stage
+        # Make this StageView work when injected, in which case `current_stage` is an instance
+        # of the base class, and we don't save any consent, as it is assumed to be a one-time
+        # prompt
+        if not isinstance(current_stage, ConsentStage):
+            return super().get(request, *args, **kwargs)
         # For always require, we always return the challenge
         if current_stage.mode == ConsentMode.ALWAYS_REQUIRE:
             return super().get(request, *args, **kwargs)
@@ -85,6 +89,11 @@ class ConsentStageView(ChallengeStageView):
         if PLAN_CONTEXT_APPLICATION not in self.executor.plan.context:
             return self.executor.stage_ok()
         application = self.executor.plan.context[PLAN_CONTEXT_APPLICATION]
+        # Make this StageView work when injected, in which case `current_stage` is an instance
+        # of the base class, and we don't save any consent, as it is assumed to be a one-time
+        # prompt
+        if not isinstance(current_stage, ConsentStage):
+            return self.executor.stage_ok()
         # Since we only get here when no consent exists, we can create it without update
         if current_stage.mode == ConsentMode.PERMANENT:
             UserConsent.objects.create(
diff --git a/tests/e2e/test_source_saml.py b/tests/e2e/test_source_saml.py
index f1a71a6f0..413b3e69a 100644
--- a/tests/e2e/test_source_saml.py
+++ b/tests/e2e/test_source_saml.py
@@ -98,12 +98,18 @@ class TestSourceSAML(SeleniumTestCase):
     @apply_migration("authentik_flows", "0008_default_flows")
     @apply_migration("authentik_flows", "0009_source_flows")
     @apply_migration("authentik_crypto", "0002_create_self_signed_kp")
+    @apply_migration(
+        "authentik_sources_saml", "0010_samlsource_pre_authentication_flow"
+    )
     @object_manager
     def test_idp_redirect(self):
         """test SAML Source With redirect binding"""
         # Bootstrap all needed objects
         authentication_flow = Flow.objects.get(slug="default-source-authentication")
         enrollment_flow = Flow.objects.get(slug="default-source-enrollment")
+        pre_authentication_flow = Flow.objects.get(
+            slug="default-source-pre-authentication"
+        )
         keypair = CertificateKeyPair.objects.create(
             name="test-idp-cert",
             certificate_data=IDP_CERT,
@@ -115,6 +121,7 @@ class TestSourceSAML(SeleniumTestCase):
             slug="saml-idp-test",
             authentication_flow=authentication_flow,
             enrollment_flow=enrollment_flow,
+            pre_authentication_flow=pre_authentication_flow,
             issuer="entity-id",
             sso_url="http://localhost:8080/simplesaml/saml2/idp/SSOService.php",
             binding_type=SAMLBindingTypes.Redirect,
@@ -158,23 +165,30 @@ class TestSourceSAML(SeleniumTestCase):
     @apply_migration("authentik_flows", "0008_default_flows")
     @apply_migration("authentik_flows", "0009_source_flows")
     @apply_migration("authentik_crypto", "0002_create_self_signed_kp")
+    @apply_migration(
+        "authentik_sources_saml", "0010_samlsource_pre_authentication_flow"
+    )
     @object_manager
     def test_idp_post(self):
         """test SAML Source With post binding"""
         # Bootstrap all needed objects
         authentication_flow = Flow.objects.get(slug="default-source-authentication")
         enrollment_flow = Flow.objects.get(slug="default-source-enrollment")
+        pre_authentication_flow = Flow.objects.get(
+            slug="default-source-pre-authentication"
+        )
         keypair = CertificateKeyPair.objects.create(
             name="test-idp-cert",
             certificate_data=IDP_CERT,
             key_data=IDP_KEY,
         )
 
-        SAMLSource.objects.create(
+        source = SAMLSource.objects.create(
             name="saml-idp-test",
             slug="saml-idp-test",
             authentication_flow=authentication_flow,
             enrollment_flow=enrollment_flow,
+            pre_authentication_flow=pre_authentication_flow,
             issuer="entity-id",
             sso_url="http://localhost:8080/simplesaml/saml2/idp/SSOService.php",
             binding_type=SAMLBindingTypes.POST,
@@ -198,7 +212,18 @@ class TestSourceSAML(SeleniumTestCase):
             By.CLASS_NAME, "pf-c-login__main-footer-links-item-link"
         ).click()
         sleep(1)
-        self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
+
+        flow_executor = self.get_shadow_root("ak-flow-executor")
+        consent_stage = self.get_shadow_root("ak-stage-consent", flow_executor)
+
+        self.assertIn(
+            source.name,
+            consent_stage.find_element(By.CSS_SELECTOR, "#header-text").text,
+        )
+        consent_stage.find_element(
+            By.CSS_SELECTOR,
+            ("[type=submit]"),
+        ).click()
 
         # Now we should be at the IDP, wait for the username field
         self.wait.until(ec.presence_of_element_located((By.ID, "username")))
@@ -220,12 +245,18 @@ class TestSourceSAML(SeleniumTestCase):
     @apply_migration("authentik_flows", "0008_default_flows")
     @apply_migration("authentik_flows", "0009_source_flows")
     @apply_migration("authentik_crypto", "0002_create_self_signed_kp")
+    @apply_migration(
+        "authentik_sources_saml", "0010_samlsource_pre_authentication_flow"
+    )
     @object_manager
     def test_idp_post_auto(self):
         """test SAML Source With post binding (auto redirect)"""
         # Bootstrap all needed objects
         authentication_flow = Flow.objects.get(slug="default-source-authentication")
         enrollment_flow = Flow.objects.get(slug="default-source-enrollment")
+        pre_authentication_flow = Flow.objects.get(
+            slug="default-source-pre-authentication"
+        )
         keypair = CertificateKeyPair.objects.create(
             name="test-idp-cert",
             certificate_data=IDP_CERT,
@@ -237,6 +268,7 @@ class TestSourceSAML(SeleniumTestCase):
             slug="saml-idp-test",
             authentication_flow=authentication_flow,
             enrollment_flow=enrollment_flow,
+            pre_authentication_flow=pre_authentication_flow,
             issuer="entity-id",
             sso_url="http://localhost:8080/simplesaml/saml2/idp/SSOService.php",
             binding_type=SAMLBindingTypes.POST_AUTO,