diff --git a/composer.json b/composer.json
index 3f3a888e8e412070292a6d408ae54a2fd53c9e22..d90a7e4ad9825d3c4ec232260b86f064a7a8fcea 100644
--- a/composer.json
+++ b/composer.json
@@ -6,6 +6,7 @@
     "require": {
         "php": ">=7.2.5",
         "ext-ctype": "*",
+        "ext-curl": "*",
         "ext-iconv": "*",
         "ext-json": "*",
         "ext-openssl": "*",
diff --git a/public/assets/css/app.css b/public/assets/css/app.css
index 63693e43081a2327a8052889687aaab35612a35a..87d8314cfa738689cf26573563abb927b47493a3 100755
--- a/public/assets/css/app.css
+++ b/public/assets/css/app.css
@@ -737,4 +737,12 @@ ul.navbar-nav.flex-row > .nav-item {
 }
 .dropdown-toggle.caret-off::after {
     display: none;
+}
+
+.alert-json {
+    text-align: left;
+}
+.alert-json > pre {
+    white-space: pre-wrap;
+    word-break: break-all;
 }
\ No newline at end of file
diff --git a/public/assets/js/app.js b/public/assets/js/app.js
index 7f8e93d6d7241c2f18bbab1aad4569d7bb4d547f..06ea52694ddf67ac1d7c297b4ceb14b2f7f4964a 100755
--- a/public/assets/js/app.js
+++ b/public/assets/js/app.js
@@ -544,8 +544,10 @@ function initializeFlashes() {
     $flashes = $('#flashes');
     if ($flashes.find('.alert').length) {
         $flashes.show();
-        window.setTimeout(function () {
-            $flashes.fadeOut(1000);
-        }, 4000);
+        if (!$flashes.find('.alert-json').length) {
+            window.setTimeout(function () {
+                $flashes.fadeOut(1000);
+            }, 4000);
+        }
     }
 }
\ No newline at end of file
diff --git a/src/Controller/OauthClientController.php b/src/Controller/OauthClientController.php
index 8b391f853b263557fb6affa54c6bff37eacfd945..2a86ea1c33d6dedcb49cd190a49145ced01d1ff8 100644
--- a/src/Controller/OauthClientController.php
+++ b/src/Controller/OauthClientController.php
@@ -6,6 +6,7 @@ use App\Entity\Entry;
 use App\Entity\Log;
 use App\Entity\OAuth2ClientProfile;
 use App\Form\ClientProfileType;
+use App\Form\CreateTokenType;
 use App\Repository\OAuth2ClientProfileRepository;
 use League\Bundle\OAuth2ServerBundle\Model\Client;
 use Doctrine\Persistence\ManagerRegistry;
@@ -19,6 +20,7 @@ use Symfony\Component\Form\FormInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\Routing\Annotation\Route;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
 
 /**
  * Paramétrage des applications clientes autorisées
@@ -131,4 +133,63 @@ class OauthClientController extends AbstractController
         return $this->redirectToRoute('app_client_index');
     }
 
+    /**
+     * @Route("/{id}/create-token", name="app_client_create_token", methods={"GET", "POST"})
+     *
+     * Un formulaire permet de saisir un nom d'utilisateur et un mot de passe, qui seront utilisés pour obtenir un token d'accès
+     */
+    public function createToken(Request $request, OAuth2ClientProfile $clientProfile): Response
+    {
+        $form = $this->createForm(CreateTokenType::class, [], [
+            'action' => $this->generateUrl('app_client_create_token', ['id' => $clientProfile->getId()]),
+        ]);
+
+        $form->handleRequest($request);
+        if ($form->isSubmitted() && $form->isValid()) {
+            $response = $this->getToken($clientProfile, $form->get('pseudo')->getData(), $form->get('password')->getData());
+//            dump(json_encode($response, JSON_PRETTY_PRINT));die();
+            $this->addFlash('json', json_encode($response, JSON_PRETTY_PRINT));
+
+            return $this->render('closeModalAndRedirect.html.twig', [
+                'url' => $this->generateUrl('app_client_index'),
+            ]);
+        }
+
+        return $this->render('genericModalForm.html.twig', [
+            'title' => "Créer un token",
+            'form' => $form->createView(),
+        ]);
+    }
+
+
+    private function getToken(OAuth2ClientProfile $clientProfile, $pseudo, $password)
+    {
+        $client = $clientProfile->getClient();
+        $params = [
+            'grant_type'     => 'password',
+            'client_id'      => $client->getIdentifier(),
+            'client_secret'  => $client->getSecret(),
+            'scope'          => 'email pseudo uuid',
+            'username'       => $pseudo,
+            'password'       => $password,
+        ];
+
+        $uri = $this->generateUrl('oauth2_token', [], UrlGeneratorInterface::ABSOLUTE_URL);
+
+        $ch = curl_init($uri);
+
+
+        $ch = curl_init($uri);
+        curl_setopt($ch, CURLOPT_POST, true);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+        $response = curl_exec($ch);
+        $response = json_decode($response, true);
+        if(curl_errno($ch)){
+            dump('Curl error: ' . curl_error($ch));die();
+        }
+        curl_close($ch);
+
+        return $response;
+    }
 }
diff --git a/src/Form/CreateTokenType.php b/src/Form/CreateTokenType.php
new file mode 100644
index 0000000000000000000000000000000000000000..c6077417abc0e838d083b1dd460eb6983d227164
--- /dev/null
+++ b/src/Form/CreateTokenType.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace App\Form;
+
+use App\Entity\Entry;
+use App\Entity\Label;
+use App\Entity\User;
+use App\Languages\LanguagesIso;
+use App\Repository\GroupRepository;
+use Symfony\Bridge\Doctrine\Form\Type\EntityType;
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
+use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
+use Symfony\Component\Form\Extension\Core\Type\DateType;
+use Symfony\Component\Form\Extension\Core\Type\PasswordType;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
+use Symfony\Component\Form\Extension\Core\Type\TextareaType;
+use Symfony\Component\Form\Extension\Core\Type\TextType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+use Symfony\Component\Security\Core\Security;
+
+class CreateTokenType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options): void
+    {
+        $builder
+            ->add('pseudo', TextType::class, [
+                'label' => 'Pseudo',
+            ])
+            ->add('password', PasswordType::class, [
+                'label' => 'Password',
+            ])
+        ;
+
+
+        $builder
+            ->add('submit', SubmitType::class, [
+                'label' => 'submit',
+            ]);
+    }
+
+    public function configureOptions(OptionsResolver $resolver): void
+    {
+        $resolver->setDefaults([
+            'attr' => [
+                'data-ajax-form' => '',
+                'data-ajax-form-target' => '#bootstrap-modal .modal-content',
+                'novalidate' => 'novalidate',
+            ],
+        ]);
+    }
+}
diff --git a/templates/_flashMessages.html.twig b/templates/_flashMessages.html.twig
index 2f672d72303fd92d44e42069d5c98610799173ac..516f9fad59a5035edd2a78c9ae26234366bd51b9 100644
--- a/templates/_flashMessages.html.twig
+++ b/templates/_flashMessages.html.twig
@@ -1,9 +1,15 @@
 {% if app.session.started %}
     {% for type, flashes in app.session.flashbag.all %}
         {% for message in flashes %}
-            <div class="alert alert-{{ type }}" role="alert">
-                {{ message|trans|raw }}
-            </div>
+                {% if type == 'json' %}
+                    <div class="alert alert-warning alert-{{ type }}" role="alert">
+                        <pre>{{ message|trans|raw }}</pre>
+                    </div>
+                {% else %}
+                    <div class="alert alert-{{ type }}" role="alert">
+                        {{ message|trans|raw }}
+                    </div>
+                {% endif %}
         {% endfor %}
     {% endfor %}
 
diff --git a/templates/oauth_client/index.html.twig b/templates/oauth_client/index.html.twig
index d5998786518d04e1faecccba8e63e0aec2733fad..f112b68fcb9b1eb72655be83cd59e581298b2fea 100644
--- a/templates/oauth_client/index.html.twig
+++ b/templates/oauth_client/index.html.twig
@@ -7,6 +7,7 @@
 
         <div class="row justify-content-center mt-5">
             <div class="col-md-12">
+
                 <h3 class="card-title d-flex justify-content-between">
                     Clients
                     <a href="{{ path('app_client_new') }}" class="btn btn-dark"><i class="bi-plus"></i> Créer</a>
@@ -41,10 +42,17 @@
                                     <td>{{ client.grants|join('<br>')|raw }}</td>
                                     <td>{{ client.scopes|join('<br>')|raw }}</td>
                                     <td>{{ client.active ? 'Yes' : 'No' }}</td>
-                                    <td class="text-end">
+
+                                    <td class="text-nowrap text-end">
+
+                                        {% if 'password' in client.grants|join(',') %}
+                                            <a title="Obtenir un token" href="#" data-url="{{ path('app_client_create_token', {'id': clientProfile.id}) }}" class="modal-form btn btn-dark btn-xs">Token</a>
+                                        {% endif %}
+
                                         <a href="{{ path('app_client_edit', {'id': clientProfile.id}) }}" class="btn btn-dark btn-xs">Modifier</a>
                                         <div class="d-inline-block">{{ include('oauth_client/_delete_form.html.twig') }}</div>
                                     </td>
+
                                 </tr>
                             {% else %}
                                 <tr>