diff --git a/src/Resources/config/reset_password_services.xml b/config/reset_password_services.xml
similarity index 100%
rename from src/Resources/config/reset_password_services.xml
rename to config/reset_password_services.xml
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
deleted file mode 100644
index dd2cdb11..00000000
--- a/src/DependencyInjection/Configuration.php
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-
-/*
- * This file is part of the SymfonyCasts ResetPasswordBundle package.
- * Copyright (c) SymfonyCasts <https://symfonycasts.com/>
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace SymfonyCasts\Bundle\ResetPassword\DependencyInjection;
-
-use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
-use Symfony\Component\Config\Definition\Builder\TreeBuilder;
-use Symfony\Component\Config\Definition\ConfigurationInterface;
-
-/**
- * @author Jesse Rushlow <jr@rushlow.dev>
- * @author Ryan Weaver   <ryan@symfonycasts.com>
- */
-final class Configuration implements ConfigurationInterface
-{
-    public function getConfigTreeBuilder(): TreeBuilder
-    {
-        $treeBuilder = new TreeBuilder('symfonycasts_reset_password');
-        /** @var ArrayNodeDefinition $rootNode */
-        $rootNode = $treeBuilder->getRootNode();
-
-        $rootNode /** @phpstan-ignore-line method.notFound (The last end() call) */
-            ->children()
-                ->scalarNode('request_password_repository')
-                    ->isRequired()
-                    ->info('A class that implements ResetPasswordRequestRepositoryInterface - usually your ResetPasswordRequestRepository.')
-                ->end()
-                ->integerNode('lifetime')
-                    ->defaultValue(3600)
-                    ->info('The length of time in seconds that a password reset request is valid for after it is created.')
-                ->end()
-                ->integerNode('throttle_limit')
-                    ->defaultValue(3600)
-                    ->info('Another password reset cannot be made faster than this throttle time in seconds.')
-                ->end()
-                ->booleanNode('enable_garbage_collection')
-                    ->defaultValue(true)
-                    ->info('Enable/Disable automatic garbage collection.')
-            ->end();
-
-        return $treeBuilder;
-    }
-}
diff --git a/src/DependencyInjection/SymfonyCastsResetPasswordExtension.php b/src/DependencyInjection/SymfonyCastsResetPasswordExtension.php
deleted file mode 100644
index 34c86c79..00000000
--- a/src/DependencyInjection/SymfonyCastsResetPasswordExtension.php
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-
-/*
- * This file is part of the SymfonyCasts ResetPasswordBundle package.
- * Copyright (c) SymfonyCasts <https://symfonycasts.com/>
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace SymfonyCasts\Bundle\ResetPassword\DependencyInjection;
-
-use Symfony\Component\Config\FileLocator;
-use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\DependencyInjection\Extension\Extension;
-use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
-use Symfony\Component\DependencyInjection\Reference;
-
-/**
- * @author Jesse Rushlow <jr@rushlow.dev>
- * @author Ryan Weaver   <ryan@symfonycasts.com>
- */
-final class SymfonyCastsResetPasswordExtension extends Extension
-{
-    public function load(array $configs, ContainerBuilder $container): void
-    {
-        $loader = new XmlFileLoader($container, new FileLocator(\dirname(__DIR__).'/Resources/config'));
-        $loader->load('reset_password_services.xml');
-
-        $configuration = $this->getConfiguration($configs, $container);
-        if (!$configuration) {
-            throw new \Exception('Configuration is not expected to be null');
-        }
-
-        $config = $this->processConfiguration($configuration, $configs);
-
-        $helperDefinition = $container->getDefinition('symfonycasts.reset_password.helper');
-        $helperDefinition->replaceArgument(2, new Reference($config['request_password_repository']));
-        $helperDefinition->replaceArgument(3, $config['lifetime']);
-        $helperDefinition->replaceArgument(4, $config['throttle_limit']);
-
-        $cleanerDefinition = $container->getDefinition('symfonycasts.reset_password.cleaner');
-        $cleanerDefinition->replaceArgument(0, new Reference($config['request_password_repository']));
-        $cleanerDefinition->replaceArgument(1, $config['enable_garbage_collection']);
-    }
-
-    public function getAlias(): string
-    {
-        return 'symfonycasts_reset_password';
-    }
-}
diff --git a/src/SymfonyCastsResetPasswordBundle.php b/src/SymfonyCastsResetPasswordBundle.php
index bd71f3a4..58e15118 100644
--- a/src/SymfonyCastsResetPasswordBundle.php
+++ b/src/SymfonyCastsResetPasswordBundle.php
@@ -9,22 +9,57 @@
 
 namespace SymfonyCasts\Bundle\ResetPassword;
 
-use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
-use Symfony\Component\HttpKernel\Bundle\Bundle;
-use SymfonyCasts\Bundle\ResetPassword\DependencyInjection\SymfonyCastsResetPasswordExtension;
+use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
 
 /**
  * @author Jesse Rushlow <jr@rushlow.dev>
  * @author Ryan Weaver   <ryan@symfonycasts.com>
  */
-class SymfonyCastsResetPasswordBundle extends Bundle
+class SymfonyCastsResetPasswordBundle extends AbstractBundle
 {
-    public function getContainerExtension(): ?ExtensionInterface
+    protected string $extensionAlias = 'symfonycasts_reset_password';
+
+    public function configure(DefinitionConfigurator $definition): void
+    {
+        $definition->rootNode() /** @phpstan-ignore method.notFound */
+            ->children()
+                ->scalarNode('request_password_repository')
+                    ->isRequired()
+                    ->info('A class that implements ResetPasswordRequestRepositoryInterface - usually your ResetPasswordRequestRepository.')
+                ->end()
+                ->integerNode('lifetime')
+                    ->defaultValue(3600)
+                    ->info('The length of time in seconds that a password reset request is valid for after it is created.')
+                ->end()
+                ->integerNode('throttle_limit')
+                    ->defaultValue(3600)
+                    ->info('Another password reset cannot be made faster than this throttle time in seconds.')
+                ->end()
+                ->booleanNode('enable_garbage_collection')
+                    ->defaultValue(true)
+                    ->info('Enable/Disable automatic garbage collection.')
+                ->end()
+            ->end()
+        ;
+    }
+
+    /** @param array<string, string|int|bool> $config */
+    public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
     {
-        if (null === $this->extension) {
-            $this->extension = new SymfonyCastsResetPasswordExtension();
-        }
+        $container->import('../config/reset_password_services.xml');
 
-        return $this->extension ?: null;
+        $container->services()
+            ->get('symfonycasts.reset_password.helper')
+                ->arg(2, new Reference((string) $config['request_password_repository']))
+                ->arg(3, $config['lifetime'])
+                ->arg(4, $config['throttle_limit'])
+            ->get('symfonycasts.reset_password.cleaner')
+                ->arg(0, new Reference((string) $config['request_password_repository']))
+                ->arg(1, $config['enable_garbage_collection'])
+        ;
     }
 }
diff --git a/src/Resources/translations/ResetPasswordBundle+intl-icu.nl.xlf b/translations/ResetPasswordBundle+intl-icu.nl.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle+intl-icu.nl.xlf
rename to translations/ResetPasswordBundle+intl-icu.nl.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.ar.xlf b/translations/ResetPasswordBundle.ar.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.ar.xlf
rename to translations/ResetPasswordBundle.ar.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.ca.xlf b/translations/ResetPasswordBundle.ca.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.ca.xlf
rename to translations/ResetPasswordBundle.ca.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.cs.xlf b/translations/ResetPasswordBundle.cs.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.cs.xlf
rename to translations/ResetPasswordBundle.cs.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.de.xlf b/translations/ResetPasswordBundle.de.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.de.xlf
rename to translations/ResetPasswordBundle.de.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.el.xlf b/translations/ResetPasswordBundle.el.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.el.xlf
rename to translations/ResetPasswordBundle.el.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.en.xlf b/translations/ResetPasswordBundle.en.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.en.xlf
rename to translations/ResetPasswordBundle.en.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.es.xlf b/translations/ResetPasswordBundle.es.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.es.xlf
rename to translations/ResetPasswordBundle.es.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.fi.xlf b/translations/ResetPasswordBundle.fi.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.fi.xlf
rename to translations/ResetPasswordBundle.fi.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.fr.xlf b/translations/ResetPasswordBundle.fr.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.fr.xlf
rename to translations/ResetPasswordBundle.fr.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.hu.xlf b/translations/ResetPasswordBundle.hu.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.hu.xlf
rename to translations/ResetPasswordBundle.hu.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.it.xlf b/translations/ResetPasswordBundle.it.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.it.xlf
rename to translations/ResetPasswordBundle.it.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.ja.xlf b/translations/ResetPasswordBundle.ja.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.ja.xlf
rename to translations/ResetPasswordBundle.ja.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.mk.xlf b/translations/ResetPasswordBundle.mk.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.mk.xlf
rename to translations/ResetPasswordBundle.mk.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.mn.xlf b/translations/ResetPasswordBundle.mn.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.mn.xlf
rename to translations/ResetPasswordBundle.mn.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.pl.xlf b/translations/ResetPasswordBundle.pl.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.pl.xlf
rename to translations/ResetPasswordBundle.pl.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.pt.xlf b/translations/ResetPasswordBundle.pt.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.pt.xlf
rename to translations/ResetPasswordBundle.pt.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.ro.xlf b/translations/ResetPasswordBundle.ro.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.ro.xlf
rename to translations/ResetPasswordBundle.ro.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.ru.xlf b/translations/ResetPasswordBundle.ru.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.ru.xlf
rename to translations/ResetPasswordBundle.ru.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.sk.xlf b/translations/ResetPasswordBundle.sk.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.sk.xlf
rename to translations/ResetPasswordBundle.sk.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.sr.xlf b/translations/ResetPasswordBundle.sr.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.sr.xlf
rename to translations/ResetPasswordBundle.sr.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.tr.xlf b/translations/ResetPasswordBundle.tr.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.tr.xlf
rename to translations/ResetPasswordBundle.tr.xlf
diff --git a/src/Resources/translations/ResetPasswordBundle.uk.xlf b/translations/ResetPasswordBundle.uk.xlf
similarity index 100%
rename from src/Resources/translations/ResetPasswordBundle.uk.xlf
rename to translations/ResetPasswordBundle.uk.xlf