diff --git a/library/Class/IdentityProvider.php b/library/Class/IdentityProvider.php
index e3052f9787c3f6202c03f6289c851aa119aeba34..3efdcc7f9c3e25adc96586b8eae98d9785e5181e 100644
--- a/library/Class/IdentityProvider.php
+++ b/library/Class/IdentityProvider.php
@@ -56,7 +56,8 @@ class Class_IdentityProvider extends Storm_Model_Abstract{
                        'nonce',
                        'logout_url',
                        'button_login',
-                       'button_logout'],
+                       'button_logout',
+                       'prod_url' ],
 
     $_context;
 
@@ -79,8 +80,8 @@ class Class_IdentityProvider extends Storm_Model_Abstract{
 
   public function isAttachable() {
     $user = Class_Users::getIdentity();
-    return !($user && $this->isRemotelyLogged())
-      && !$this->isAssociatedTo($user);
+    return !($user && $this->isRemotelyLogged());
+//      && !$this->isAssociatedTo($user);
   }
 
 
@@ -212,6 +213,7 @@ class Class_IdentityProvider extends Storm_Model_Abstract{
     $config = $this->getConfigAsArray();
     $config[$key] = $value;
     $this->setConfig(json_encode($config));
+    return $this;
   }
 
 
diff --git a/library/Class/IdentityProvider/Franceconnect.php b/library/Class/IdentityProvider/Franceconnect.php
index 334ecf541b90d1bcb38e413a3adeb7047a81d496..39acbf3b071f9dd8d5cc9e54166a32948522ab89 100644
--- a/library/Class/IdentityProvider/Franceconnect.php
+++ b/library/Class/IdentityProvider/Franceconnect.php
@@ -22,10 +22,10 @@
 
 class Class_IdentityProvider_Franceconnect extends Class_IdentityProvider_Default {
   protected $_script_logout = '<div id="fconnect-profile" data-fc-logout-url="[URL]"><a href="#">[USERNAME]</a></div>
-<script src="https://fcp.integ01.dev-franceconnect.fr/js/franceconnect.js"></script>';
+<script src="[URL_FC]/js/franceconnect.js"></script>';
 
-  protected  $_config = ['url' => 'https://fcp.integ01.dev-franceconnect.fr/api/v1',
-                         'logout_url' => 'https://fcp.integ01.dev-franceconnect.fr/api/v1/logout',
+  protected  $_config = ['url' => '[URL_FC]/api/v1',
+                         'logout_url' => '[URL_FC]/api/v1/logout',
                          'button_login' => 'franceconnect',
   ];
 
@@ -35,7 +35,16 @@ class Class_IdentityProvider_Franceconnect extends Class_IdentityProvider_Defaul
   }
 
 
+  public function getFranceConnectUrl() {
+    return parent::getParam('prod_url')
+      ? 'https://app.franceconnect.gouv.fr'
+      :'https://fcp.integ01.dev-franceconnect.fr';
+  }
+
+
   public function getParam($key) {
+    $this->_config['url'] = str_replace('[URL_FC]',$this->getFranceConnectUrl(),$this->_config['url']);
+    $this->_config['logout_url'] = str_replace('[URL_FC]',$this->getFranceConnectUrl(),$this->_config['logout_url']);
     return 'button_logout' == $key
       ? $this->_buttonLogout()
       : parent::getParam($key);
@@ -50,6 +59,8 @@ class Class_IdentityProvider_Franceconnect extends Class_IdentityProvider_Defaul
                                                         'provider' => $this->_provider->getId()]),
                           $script);
 
+    $script = str_replace('[URL_FC]',$this->getFranceConnectUrl(),$script);
+
     if ($user = Class_Users::getIdentity())
       return str_replace('[USERNAME]', $user->getNomAff(), $script);
 
diff --git a/library/Class/Testing/PhpCommand.php b/library/Class/Testing/PhpCommand.php
index a4137afc850f3e12fcec53ad90326d3d328d4cea..0bea95abc047254d520c631049d2294e5d82decb 100644
--- a/library/Class/Testing/PhpCommand.php
+++ b/library/Class/Testing/PhpCommand.php
@@ -23,6 +23,7 @@ class Class_Testing_PhpCommand extends Class_Testing_FileSystem {
   public function __construct() {
     $this->_known_functions = array_merge($this->_known_functions,
                                           ['rand',
+                                           'sha1',
                                            'hash',
                                            'password_hash',
                                            'extension_loaded',
diff --git a/library/Class/WebService/Acheteza.php b/library/Class/WebService/Acheteza.php
index 81c13dce5e358daec6d738f674c8f4c583b7cfe2..c6b7acb7b74863889173681da2a7844add6e4b12 100644
--- a/library/Class/WebService/Acheteza.php
+++ b/library/Class/WebService/Acheteza.php
@@ -29,18 +29,11 @@ class Class_WebService_Acheteza extends Class_WebService_IdentityProvider {
         || (!$pan = $context->getParam('pan')))
       return $this;
 
-    /*
-      if (!$this->_checkAccessToken($token, $pan))
+
+    if (!$this->_checkAccessToken($token, $pan))
       return $this;
-    */
 
     $this->loginWith($pan);
-    return $this;
-
-    /*
-      if ($id = $this->_getRemoteId($token))
-      $this->loginWith($id);
-    */
 
     return $this;
   }
diff --git a/library/Class/WebService/IdentityProvider.php b/library/Class/WebService/IdentityProvider.php
index 219dcb49962aa23f96bef9e0fec36a2517f30409..868b2a3db46e47eb0999e5edb16999a1b28dcbc6 100644
--- a/library/Class/WebService/IdentityProvider.php
+++ b/library/Class/WebService/IdentityProvider.php
@@ -23,26 +23,45 @@
 abstract class Class_WebService_IdentityProvider {
   use Trait_SimpleWebClient, Trait_TimeSource;
 
-  /** @var ZendAfi_Session_Namespace */
-  protected static $_session_namespace;
+  /** @var array of ZendAfi_Session_Namespace */
+  protected static $_session_namespace = [],
+        $_expiration_delay = 300;
 
   /** @var Class_IdentityProvider */
   protected $_provider;
 
+
   /** @return ZendAfi_Session_Namespace */
   public static function getSession() {
-    if (static::$_session_namespace)
-      return static::$_session_namespace;
 
-    static::$_session_namespace = (new ZendAfi_Session_Namespace(md5(BASE_URL . get_called_class())))
-      ->setExpirationDelay(300);
+    $called_class  = get_called_class();
+    if (isset(static::$_session_namespace[$called_class]))
+      return static::$_session_namespace[$called_class];
+
+    static::$_session_namespace[$called_class] = (new ZendAfi_Session_Namespace(md5(BASE_URL . get_called_class())))
+      ->setExpirationDelay(static::$_expiration_delay);
+
+    return static::$_session_namespace[$called_class];
+  }
+
 
-    return static::$_session_namespace;
+  public static function setExpirationDelay($expires_at) {
+    static::$_session_namespace[get_called_class()]->setExpirationDelay($expires_at);
+    static::$_expiration_delay = $expires_at;
   }
 
 
   public static function clearSession() {
     static::getSession()->unsetAll();
+    static::$_session_namespace[get_called_class()] = null;
+  }
+
+
+  public static function clearAllSession() {
+    foreach (static::$_session_namespace as $namespace) {
+      static::$_session_namespace[$namespace]->unsetAll();
+      static::$_session_namespace[$namespace] = null;
+    }
   }
 
 
diff --git a/library/Class/WebService/OpenId.php b/library/Class/WebService/OpenId.php
index 21744ea8c7a6ebf131385bbacbc8019044dba5e8..99d35982061c465d62b4b0b81730a4ae5433b5a6 100644
--- a/library/Class/WebService/OpenId.php
+++ b/library/Class/WebService/OpenId.php
@@ -23,12 +23,13 @@ require_once 'library/php-jwt/autoload.php';
 require_once 'library/phpseclib/autoload.php';
 
 class Class_WebService_OpenId extends Class_WebService_IdentityProvider {
+  use Trait_StaticPhpCommand;
 
   protected
     $_client_id,
     $_client_secret = '' ,
     $_url='',
-    $_nonce = true,
+    $_nonce,
     $_authorization_url = '',
     $_token_url = '',
     $_userinfo_url = '',
@@ -43,6 +44,7 @@ class Class_WebService_OpenId extends Class_WebService_IdentityProvider {
 
 
   public static function getUserId() {
+
     if (!static::isLogged())
       return null;
 
@@ -133,12 +135,14 @@ class Class_WebService_OpenId extends Class_WebService_IdentityProvider {
 
 
   public function getUserInfos($code, $state) {
+
     if (isset($this->getSession()->userinfo))
       return $this->getSession()->userinfo;
 
     if ($state != $this->getState())
       return false;
 
+
     if (!$access_token = $this->_getAndCheckAccessToken($code))
       return [];
 
@@ -166,13 +170,15 @@ class Class_WebService_OpenId extends Class_WebService_IdentityProvider {
 
 
   protected function _checkNonce($nonce) {
-    return $this->getNonce() == $nonce;
+    return ($this->getNonce() == $nonce);
   }
 
 
   protected function _getAndCheckAccessToken($code) {
-    if (isset($this->getSession()->access_token))
+    if (isset($this->getSession()->access_token)) {
+      $this->setExpirationDelay($this->getSession()->expires_in);
       return $this->getSession()->access_token;
+    }
 
     $http_client = $this->getWebClient();
     $post_data = [
@@ -187,17 +193,29 @@ class Class_WebService_OpenId extends Class_WebService_IdentityProvider {
                                           'application/json');
 
     $json = json_decode($response);
+
     if (!isset($json->access_token)|| !isset($json->id_token))
       return ;
 
     $this->getSession()->access_token = $json->access_token;
+    if (isset($json->expires_in)) {
+          $this->setExpirationDelay($json->expires_in);
+          $this->getSession()->expires_in = $json->expires_in;
+    }
+
+    $this->getSession()->token = $json->id_token;
 
-    if (!$this->_nonce)
+    if (!$this->_nonce) {
       return $json->access_token;
+    }
+
 
     if (! $certifs = $this->_getCertificates())
       $certifs = $this->_client_secret;
 
+    \Firebase\JWT\JWT::$leeway = 2;
+
+
     $response =\Firebase\JWT\JWT::decode($json->id_token,
                                          $certifs,
                                          ['HS256','RS256']);
@@ -208,7 +226,6 @@ class Class_WebService_OpenId extends Class_WebService_IdentityProvider {
     if (!$this->_checkNonce($response->nonce))
       return ;
 
-    $this->getSession()->token = $json->id_token;
     return $json->access_token;
   }
 
@@ -238,7 +255,7 @@ class Class_WebService_OpenId extends Class_WebService_IdentityProvider {
         && ($state = $this->getSession()->state))
       return $state;
 
-    return $this->_getRandomToken();
+    return $this->getSession()->state = $this->_getRandomToken();
   }
 
 
@@ -252,7 +269,7 @@ class Class_WebService_OpenId extends Class_WebService_IdentityProvider {
 
 
   protected function _getRandomToken(){
-    return sha1(mt_rand(0, mt_getrandmax()));
+    return $this->getPhpCommand()->sha1(mt_rand(0, mt_getrandmax()));
   }
 
 
@@ -278,8 +295,8 @@ class Class_WebService_OpenId extends Class_WebService_IdentityProvider {
                'scope' => 'openid',
                'state' => $this->getState()];
 
-    if ($this->_nonce)
-      $params['nonce'] = $this->getNonce();
+//    if ($this->_nonce)
+    $params['nonce'] = $this->getNonce();
 
     return $this->_authorization_url . '?' . http_build_query($params);
   }
diff --git a/library/ZendAfi/Form/Admin/IdentityProvider.php b/library/ZendAfi/Form/Admin/IdentityProvider.php
index 436c83113b5023034f0d5f80b76f81de35320b39..8282bdac1ec425174f8ad7e2721353e3c3716df2 100644
--- a/library/ZendAfi/Form/Admin/IdentityProvider.php
+++ b/library/ZendAfi/Form/Admin/IdentityProvider.php
@@ -25,7 +25,9 @@ class ZendAfi_Form_Admin_IdentityProvider extends ZendAfi_Form {
     parent::init();
 
     Class_ScriptLoader::getInstance()
-      ->addJQueryBackEnd('formSelectToggleVisibilityForElement("#type", $("#url, #url_api, #button_logout, #logout_url").closest("tr"), ["default", "acheteza"]);');
+      ->addJQueryBackEnd('formSelectToggleVisibilityForElement("#type", $("#url, #url_api, #button_logout, #logout_url").closest("tr"), ["default", "acheteza"]);')
+      ->addJQueryBackEnd('formSelectToggleVisibilityForElement("#type", $("#prod_url").closest("tr"), ["franceconnect"]);');
+
 
     $this
       ->addElement('text',
@@ -46,14 +48,14 @@ class ZendAfi_Form_Admin_IdentityProvider extends ZendAfi_Form {
 
       ->addElement('text',
                    'client_id',
-                   ['label' => $this->_('client_id'),
+                   ['label' => $this->_('Identifiant client'),
                     'size' => 50,
                     'required' => true,
                     'allowEmpty' => false])
 
       ->addElement('text',
                    'client_secret',
-                   ['label' => $this->_('client_secret'),
+                   ['label' => $this->_('Clé secrète'),
                     'size' => 50,
                     'required' => true,
                     'allowEmpty' => false])
@@ -82,6 +84,11 @@ class ZendAfi_Form_Admin_IdentityProvider extends ZendAfi_Form {
                    ['label' => $this->_('Url de logout'),
                     'title' => $this->_('Url de logout')])
 
+      ->addElement('checkbox',
+                   'prod_url',
+                   ['label' => $this->_('En production'),
+                    'title' => $this->_('En production')])
+
       ->addUniqDisplayGroup('provider');
   }
 }
diff --git a/library/ZendAfi/Session/Namespace.php b/library/ZendAfi/Session/Namespace.php
index 851dad44001b9d5744d29a32f498190d385dfcd6..157bab066ecf6559be68b34b53a4ffdac71765e8 100644
--- a/library/ZendAfi/Session/Namespace.php
+++ b/library/ZendAfi/Session/Namespace.php
@@ -30,7 +30,7 @@ class ZendAfi_Session_Namespace extends Zend_Session_Namespace {
   public function __construct($namespace = 'Default', $singleInstance = false) {
     parent::__construct($namespace, $singleInstance);
     if ($this->_isExpired())
-      $this->unsetAll();
+        $this->unsetAll();
   }
 
 
@@ -45,10 +45,19 @@ class ZendAfi_Session_Namespace extends Zend_Session_Namespace {
 
   public function setExpirationDelay($seconds) {
     $this->_expiration_delay = (int)$seconds;
+
+    parent::__set(static::EXPIRATION_VAR_NAME,
+                  $this->getTimeSource()->time() + $this->_expiration_delay);
+
     return $this;
   }
 
 
+  public function getExpirationDelay() {
+    return $this->_expiration_delay;
+  }
+
+
   protected function _isExpired() {
     $expires_at = $this->__get(static::EXPIRATION_VAR_NAME);
     return isset($expires_at) && $this->getTimeSource()->time() > $expires_at;
diff --git a/public/opac/css/global.css b/public/opac/css/global.css
index 9d1a4f995cf64af8c3baffb35e6a57a4fded6e19..0d021851a4eab7e0d3299ba6fc2abe44897d482c 100644
--- a/public/opac/css/global.css
+++ b/public/opac/css/global.css
@@ -3817,3 +3817,4 @@ a[href*="bookmarked-searches/notify"] img {
 /* identity provider widget */
 .boite.identity_provider .contenu {overflow:visible}
 .boite.identity_provider #fconnect-profile {margin: 20px 10px}
+.boite.identity_provider #fconnect-access {position: relative!important}
diff --git a/tests/scenarios/IdentityProvider/IdentityProviderAuthenticationTest.php b/tests/scenarios/IdentityProvider/IdentityProviderAuthenticationTest.php
index 510c3692aec4736526862a8fcca686d31983cfae..ee3a6311080fa63d8058cb2440f4200a9351a125 100644
--- a/tests/scenarios/IdentityProvider/IdentityProviderAuthenticationTest.php
+++ b/tests/scenarios/IdentityProvider/IdentityProviderAuthenticationTest.php
@@ -278,20 +278,19 @@ abstract class IdentityProviderAuthenticationCallbackAuthenticationTestCase
                                         'iss'=>'http://franceconnect.gouv.fr',
                                         'sub'=>'YWxhY3JpdMOp',
                                         'idp'=> 'FC',
-                                        'nonce'=>'1234'
+                                        'nonce'=>'1234',
                                        ],
                                        '8888');
 
     $response_token = json_encode(['access_token' => 1111,
                                    'token_type' => 'Bearer',
-                                   'expires_in' => '60',
+                                   'expires_in' => 60,
                                    'id_token' => $token]);
     $web_client = $this->mock();
     $web_client
       ->whenCalled('open_url')
       ->with('https://fcp.integ01.dev-franceconnect.fr/api/v1/.well-known/openid-configuration')
       ->answers(null)
-
       ->whenCalled('open_url')
       ->with('https://fcp.integ01.dev-franceconnect.fr/api/v1/userinfo?schema=openid',
              ['headers' => 'Authorization: Bearer 1111'])
@@ -324,9 +323,28 @@ abstract class IdentityProviderAuthenticationCallbackAuthenticationTestCase
     Class_WebService_OpenId::clearSession();
     parent::tearDown();
   }
+
+
+
 }
 
 
+class IdentityProviderAuthenticationOpenIdFCTest extends IdentityProviderAuthenticationCallbackAuthenticationTestCase  {
+
+  /** @test */
+  public function successSigbShouldSetExpirationDelay() {
+    $time_source = new TimeSourceForTest('2020-02-17 10:21:38');
+    Class_WebService_OpenId::setPhpCommand($this->mock()->whenCalled('sha1')->answers('mystate'));
+
+    ZendAfi_Auth::getInstance()->clearIdentity();
+    $this->postDispatch('/auth/login/provider/1/code/1233/state/mystate',
+                        ['username' => 'name@server.tld',
+                         'password' => '1987']);
+
+    $this->assertEquals(60,Class_WebService_IdentityProvider::getSession()->getExpirationDelay());
+  }
+}
+
 
 
 class IdentityProviderAuthenticationConnectedOpenidUserTest
@@ -376,6 +394,48 @@ class IdentityProviderAuthenticationConnectedOpenidUserTest
 }
 
 
+class IdentityProviderAuthenticationConnectedBokehNotConnectedOpenidUserTest
+  extends IdentityProviderAuthenticationCallbackAuthenticationTestCase {
+
+  public function setUp() {
+    parent::setUp();
+    ZendAfi_Auth::getInstance()->logUser(Class_Users::find(33));
+    Class_WebService_OpenId::getSession()->userinfo = null;
+
+    $simple_widgets = ['modules' => ['1' => ['division' => '1',
+                                             'type_module' => 'IDENTITY_PROVIDER',
+                                             'preferences' => []],
+      ]];
+
+    $this->fixture('Class_User_Identity',
+                   ['id' => 1,
+                    'provider_id' => 1,
+                    'user_id' => 33,
+                    'identifier' => 1232
+                   ]);
+
+    Class_Profil::getCurrentProfil()
+      ->setCfgAccueil($simple_widgets)
+      ->save();
+
+    $this->dispatch('/opac/index');
+  }
+
+
+  /** @test */
+  public function buttonLoginFCShouldBePresent() {
+    $this->assertXPath('//button[contains(@data-url,"/identity-providers/authenticate/id")]', $this->_response->getBody());
+  }
+
+
+  /** @test */
+  public function titleShouldBeCompteAssocie() {
+    $this->assertXPathContentContains('//div[@class="titre"]//h1','Associer votre compte',$this->_response->getBody());
+  }
+
+}
+
+
 
 
 class IdentityProviderAuthenticationLoggedUserTest extends IdentityProviderAuthenticationCallbackAuthenticationTestCase {
@@ -428,6 +488,32 @@ class IdentityProviderAuthenticationShouldDisplayButtonWithFCUrl
   }
 
 
+
+  /** @test */
+  public function authenticationToFranceConnectProdShouldRedirectToFranceConnectAuthorize() {
+    Class_IdentityProvider::find(1)->setConfigValue( 'prod_url',1)->save();
+    $web_client = $this->mock();
+    $web_client
+         ->whenCalled('open_url')
+         ->with('https://app.franceconnect.gouv.fr/api/v1/.well-known/openid-configuration')
+         ->answers(null);
+    Class_WebService_OpenId::setWebClient($web_client);
+
+
+    $_SERVER['HTTP_REFERER'] = 'referer';
+    $this->_state = base64_encode('http://bokeh.org/mycurrenturl');
+    $session = Class_WebService_OpenId::getSession();
+    $session->state = $this->_state;
+    $session->nonce = $this->_nonce;
+
+    $this->dispatch('/identity-providers/authenticate/id/1/redirect/'.urlencode('http://bokeh.org/mycurrenturl'));;
+
+    $this->assertRedirectTo('https://app.franceconnect.gouv.fr/api/v1/authorize?response_type=code&client_id=1234&redirect_uri='.urlencode('http://localhost'.BASE_URL.'/auth/login/provider/1').'&scope=openid&state='.urlencode($this->_state) . "&nonce=" . $this->_nonce);
+  }
+
+
+
+
   public function tearDown() {
     unset($_SERVER['HTTP_REFERER']);
     parent::tearDown();
@@ -547,7 +633,7 @@ class IdentityProviderAuthenticationDissociateUserTest
 
   /** @test */
   public function sessionShouldBeCleared() {
-    $this->assertEmpty(Class_WebService_OpenId::getSession()->getIterator());
+    $this->assertNull(Class_WebService_OpenId::getSession()->userinfo);
   }
 }
 
@@ -569,7 +655,8 @@ class IdentityProviderAuthenticationCallbackAuthentication
     $this->fixture('Class_IdentityProvider',
                    ['id' => 12,
                     'label' => 'FranceConnect',
-                    'type' => 'franceconnect']);
+                    'type' => 'franceconnect',
+                   ]);
   }
 
 
@@ -617,11 +704,16 @@ class IdentityProviderAuthenticationCallbackAuthentication
 
 
   /** @test */
-  public function logoutShouldRemoveOpenIdInSession() {
+  public function logoutShouldRemoveOpenIdTokeAndStateInSession() {
     Class_WebService_OpenId::getSession()->userinfo = '999';
+    Class_WebService_OpenId::getSession()->token = '999';
+    Class_WebService_OpenId::getSession()->state = '999';
     ZendAfi_Auth::getInstance()->logUser(Class_Users::find(33));
+
     $this->dispatch('/auth/logout');
-    $this->assertEmpty(Class_WebService_OpenId::getSession()->getIterator());
+    $this->assertNull(Class_WebService_OpenId::getSession()->userinfo);
+    $this->assertNull(Class_WebService_OpenId::getSession()->token);
+    $this->assertNull(Class_WebService_OpenId::getSession()->state);
   }
 
 
@@ -635,7 +727,7 @@ class IdentityProviderAuthenticationCallbackAuthentication
     ZendAfi_Auth::getInstance()->logUser(Class_Users::find(33));
     $this->dispatch('/auth/logout/provider/1');
 
-    $this->assertEmpty(Class_WebService_OpenId::getSession()->getIterator());
+    $this->assertNull(Class_WebService_OpenId::getSession()->userinfo);
     $this->assertRedirectTo('https://fcp.integ01.dev-franceconnect.fr/api/v1/logout?id_token_hint=mytoken&state=6&post_logout_redirect_uri='.urlencode(Class_Url::absolute([], null, true)));
     $this->assertEmpty(Class_Users::getIdentity());
   }
@@ -670,7 +762,7 @@ class IdentityProviderAuthenticationAbonneListTest
 
 
   /** @test */
-  public function withioutAssociatedFSMessageShouldBeDisplayed() {
+  public function withoutAssociatedFSMessageShouldBeDisplayed() {
     $this->dispatch('/abonne/associated-providers');
     $this->assertXPathContentContains('//p', 'Votre compte n\'est pas associé ', $this->_response->getBody());
   }
@@ -869,12 +961,12 @@ class IdentityProviderAuthenticationAuthLoginWithPanAchetezaTest
                 ->whenCalled('isError')->answers(false)
                 ->whenCalled('getBody')->answers('{"success":"true"}'))
 
-      /*
-      ->whenCalled('open_url')
-      ->with('http://api.crm.server.com/api/v2.3/me',
-             ['headers' => ['Authorization: Bearer MYACCESSTOKEN']])
-      ->answers(json_encode(['id' => '95fbcb97-6461-48de-8923-ef4f1de30409']))
-      */
+
+        ->whenCalled('open_url')
+        ->with('http://api.crm.server.com/api/v2.3/me',
+        ['headers' => ['Authorization: Bearer MYACCESSTOKEN']])
+        ->answers(json_encode(['id' => '95fbcb97-6461-48de-8923-ef4f1de30409']))
+
       ;
 
     $this->dispatch('/auth/login/provider/5?access_token=MYACCESSTOKEN&pan=8839');
@@ -898,6 +990,13 @@ class IdentityProviderAuthenticationAuthLoginWithPanAchetezaTest
   public function pageShouldDisplayConnectedToAcheteza() {
     $this->assertXPathContentContains('//p', 'Vous êtes connecté à Acheteza');
   }
+
+
+  /** @test */
+  public function logoutBokehShouldLogoutAcheteza() {
+    $this->dispatch('/auth/logout');
+    $this->assertRedirect('/');
+  }
 }
 
 
@@ -1071,6 +1170,17 @@ class IdentityProviderAuthenticationAuthLoginSigbAchetezaTest
   }
 
 
+  /** @test */
+  public function logoutShouldCleanSession() {
+    Class_WebService_Acheteza::getSession()->id = '999';
+    ZendAfi_Auth::getInstance()->logUser(Class_Users::find(33));
+    $this->dispatch('/auth/logout');
+    $this->assertNull(Class_WebService_Acheteza::getSession()->userinfo);
+    $this->assertNull(Class_WebService_Acheteza::getSession()->token);
+    $this->assertNull(Class_WebService_Acheteza::getSession()->state);
+  }
+
+
   /** @test */
   public function logoutProviderShouldRedirectToProviderLogoutUrl() {
     ZendAfi_Auth::getInstance()->logUser(Class_Users::find(33));
@@ -1105,11 +1215,28 @@ class IdentityProviderAuthenticationExpiringSessionAchetezaTest
 
   /** @test */
   public function notLoggedRemoteIdShouldBeCleared() {
-    ZendAfi_Session_Namespace::setTimeSource(new TimeSourceForTest('2020-02-17 10:20:38'));
-    Class_WebService_Acheteza::loginWith(9763);
-    // jump to future past expiration time of 300s
-    ZendAfi_Session_Namespace::setTimeSource(new TimeSourceForTest('2020-02-17 10:55:38'));
+    $time_source = new TimeSourceForTest('2020-02-17 10:21:38');
+    $_SESSION[md5(BASE_URL . 'Class_WebService_Acheteza')]  = ['id' =>  9763,
+                                                               'expires_at' => $time_source->time()-10];
+    ZendAfi_Session_Namespace::setTimeSource($time_source);
     $this->dispatch('/opac/index/index');
     $this->assertNull(Class_IdentityProvider::find(5)->getRemoteUserId());
   }
+
+
+  /** @test */
+  public function notLoggedRemoteIdShouldBeNotClearedIfNotExpired() {
+    $time_source = new TimeSourceForTest('2020-02-17 10:21:38');
+    $_SESSION[md5(BASE_URL . 'Class_WebService_Acheteza')]  = ['id' =>  9763,
+                                                               'expires_at' =>  $time_source->time()+10 ];
+
+    ZendAfi_Session_Namespace::setTimeSource($time_source);
+    $this->dispatch('/opac/index/index');
+    $this->assertEquals(9763,Class_IdentityProvider::find(5)->getRemoteUserId());
+  }
+
+  public function tearDown() {
+    unset($_SESSION[md5(BASE_URL . 'Class_WebService_Acheteza')]);
+    parent::tearDown();
+  }
 }
\ No newline at end of file