RECLAIM/OIDC: code cleanup
[oweals/gnunet.git] / src / reclaim / plugin_rest_openid_connect.c
index 0a6dd2b61729f02c44b514c531d66863533a6b86..053aa2f4fb87ce7011252335d80b64eaad66656d 100644 (file)
@@ -1,6 +1,6 @@
 /*
    This file is part of GNUnet.
-   Copyright (C) 2012-2015 GNUnet e.V.
+   Copyright (C) 2012-2018 GNUnet e.V.
 
    GNUnet is free software: you can redistribute it and/or modify it
    under the terms of the GNU Affero General Public License as published
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Affero General Public License for more details.
-  
+
    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+     SPDX-License-Identifier: AGPL3.0-or-later
    */
 /**
  * @author Martin Schanzenbach
  * @brief GNUnet Namestore REST plugin
  *
  */
-
 #include "platform.h"
-#include "gnunet_rest_plugin.h"
-#include "gnunet_identity_service.h"
+#include <inttypes.h>
+#include <jansson.h>
+
 #include "gnunet_gns_service.h"
 #include "gnunet_gnsrecord_lib.h"
+#include "gnunet_identity_service.h"
 #include "gnunet_namestore_service.h"
-#include "gnunet_rest_lib.h"
-#include "gnunet_jsonapi_lib.h"
-#include "gnunet_jsonapi_util.h"
-#include "microhttpd.h"
-#include <jansson.h>
-#include <inttypes.h>
-#include "gnunet_signatures.h"
 #include "gnunet_reclaim_attribute_lib.h"
 #include "gnunet_reclaim_service.h"
-#include "jwt.h"
-
+#include "gnunet_rest_lib.h"
+#include "gnunet_rest_plugin.h"
+#include "gnunet_signatures.h"
+#include "microhttpd.h"
+#include "oidc_helper.h"
 /**
  * REST root namespace
  */
  */
 #define GNUNET_REST_API_NS_LOGIN "/openid/login"
 
-/**
- * Attribute key
- */
-#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE "attribute"
-
-/**
- * Ticket key
- */
-#define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket"
-
-
-/**
- * Value key
- */
-#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE_VALUE "value"
-
 /**
  * State while collecting all egos
  */
  */
 #define OIDC_NONCE_KEY "nonce"
 
+/**
+ * OIDC cookie expiration (in seconds)
+ */
+#define OIDC_COOKIE_EXPIRATION 3
+
 /**
  * OIDC cookie header key
  */
  */
 #define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
 
+/**
+ * OIDC cookie header if user cancelled
+ */
+#define OIDC_COOKIE_HEADER_ACCESS_DENIED "Identity=Denied"
+
 /**
  * OIDC expected response_type while authorizing
  */
  */
 #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
 
+/**
+ * OIDC error key for invalid client
+ */
+#define OIDC_ERROR_KEY_INVALID_CLIENT "invalid_client"
+
+/**
+ * OIDC error key for invalid scopes
+ */
+#define OIDC_ERROR_KEY_INVALID_SCOPE "invalid_scope"
+
+/**
+ * OIDC error key for invalid requests
+ */
+#define OIDC_ERROR_KEY_INVALID_REQUEST "invalid_request"
+
+/**
+ * OIDC error key for invalid tokens
+ */
+#define OIDC_ERROR_KEY_INVALID_TOKEN "invalid_token"
+
+/**
+ * OIDC error key for invalid cookies
+ */
+#define OIDC_ERROR_KEY_INVALID_COOKIE "invalid_cookie"
+
+/**
+ * OIDC error key for generic server errors
+ */
+#define OIDC_ERROR_KEY_SERVER_ERROR "server_error"
+
+/**
+ * OIDC error key for unsupported grants
+ */
+#define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE "unsupported_grant_type"
+
+/**
+ * OIDC error key for unsupported response types
+ */
+#define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE "unsupported_response_type"
+
+/**
+ * OIDC error key for unauthorized clients
+ */
+#define OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT "unauthorized_client"
+
+/**
+ * OIDC error key for denied access
+ */
+#define OIDC_ERROR_KEY_ACCESS_DENIED "access_denied"
+
+
 /**
  * OIDC ignored parameter array
  */
-static char* OIDC_ignored_parameter_array [] =
-{
-  "display",
-  "prompt",
-  "ui_locales", 
-  "response_mode",
-  "id_token_hint",
-  "login_hint", 
-  "acr_values"
-};
+static char *OIDC_ignored_parameter_array[] = {"display",
+                                               "prompt",
+                                               "ui_locales",
+                                               "response_mode",
+                                               "id_token_hint",
+                                               "login_hint",
+                                               "acr_values"};
 
 /**
- * OIDC authorized identities and times hashmap
+ * OIDC Hash map that keeps track of issued cookies
  */
-struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time;
+struct GNUNET_CONTAINER_MultiHashMap *OIDC_cookie_jar_map;
 
 /**
  * OIDC authorized identities and times hashmap
@@ -186,14 +227,15 @@ struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time;
 struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants;
 
 /**
- * OIDC ticket/code use only once
+ * OIDC Hash map that keeps track of used authorization code(s)
  */
-struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once;
+struct GNUNET_CONTAINER_MultiHashMap *OIDC_used_ticket_map;
 
 /**
- * OIDC access_token to ticket and ego
+ * Hash map that links the issued access token to the corresponding ticket and
+ * ego
  */
-struct GNUNET_CONTAINER_MultiHashMap *OIDC_interpret_access_token;
+struct GNUNET_CONTAINER_MultiHashMap *OIDC_access_token_map;
 
 /**
  * The configuration handle
@@ -203,7 +245,7 @@ const struct GNUNET_CONFIGURATION_Handle *cfg;
 /**
  * HTTP methods allows for this plugin
  */
-static charallow_methods;
+static char *allow_methods;
 
 /**
  * @brief struct returned by the initialization function of the plugin
@@ -258,11 +300,15 @@ struct OIDC_Variables
    */
   char *login_identity;
 
+  /**
+   * User cancelled authorization/login
+   */
+  int user_cancelled;
+
   /**
    * The response JSON
    */
   json_t *response;
-
 };
 
 /**
@@ -339,6 +385,16 @@ struct RequestHandle
    */
   struct GNUNET_REST_RequestHandle *rest_handle;
 
+  /**
+   * GNS handle
+   */
+  struct GNUNET_GNS_Handle *gns_handle;
+
+  /**
+   * GNS lookup op
+   */
+  struct GNUNET_GNS_LookupRequest *gns_op;
+
   /**
    * Handle to NAMESTORE
    */
@@ -414,6 +470,16 @@ struct RequestHandle
    */
   char *tld;
 
+  /**
+   * The redirect prefix
+   */
+  char *redirect_prefix;
+
+  /**
+   * The redirect suffix
+   */
+  char *redirect_suffix;
+
   /**
    * Error response message
    */
@@ -428,12 +494,6 @@ struct RequestHandle
    * Reponse code
    */
   int response_code;
-
-  /**
-   * Response object
-   */
-  struct GNUNET_JSONAPI_Document *resp_object;
-
 };
 
 /**
@@ -447,10 +507,7 @@ cleanup_handle (struct RequestHandle *handle)
   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp;
   struct EgoEntry *ego_entry;
   struct EgoEntry *ego_tmp;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Cleaning up\n");
-  if (NULL != handle->resp_object)
-    GNUNET_JSONAPI_document_delete (handle->resp_object);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
   if (NULL != handle->timeout_task)
     GNUNET_SCHEDULER_cancel (handle->timeout_task);
   if (NULL != handle->identity_handle)
@@ -461,50 +518,43 @@ cleanup_handle (struct RequestHandle *handle)
     GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
   if (NULL != handle->idp)
     GNUNET_RECLAIM_disconnect (handle->idp);
-  if (NULL != handle->url)
-    GNUNET_free (handle->url);
-  if (NULL != handle->tld)
-    GNUNET_free (handle->tld);
-  if (NULL != handle->emsg)
-    GNUNET_free (handle->emsg);
-  if (NULL != handle->edesc)
-    GNUNET_free (handle->edesc);
+  GNUNET_free_non_null (handle->url);
+  GNUNET_free_non_null (handle->tld);
+  GNUNET_free_non_null (handle->redirect_prefix);
+  GNUNET_free_non_null (handle->redirect_suffix);
+  GNUNET_free_non_null (handle->emsg);
+  GNUNET_free_non_null (handle->edesc);
+  if (NULL != handle->gns_op)
+    GNUNET_GNS_lookup_cancel (handle->gns_op);
+  if (NULL != handle->gns_handle)
+    GNUNET_GNS_disconnect (handle->gns_handle);
+
   if (NULL != handle->namestore_handle)
     GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
   if (NULL != handle->oidc)
   {
-    if (NULL != handle->oidc->client_id)
-      GNUNET_free(handle->oidc->client_id);
-    if (NULL != handle->oidc->login_identity)
-      GNUNET_free(handle->oidc->login_identity);
-    if (NULL != handle->oidc->nonce)
-      GNUNET_free(handle->oidc->nonce);
-    if (NULL != handle->oidc->redirect_uri)
-      GNUNET_free(handle->oidc->redirect_uri);
-    if (NULL != handle->oidc->response_type)
-      GNUNET_free(handle->oidc->response_type);
-    if (NULL != handle->oidc->scope)
-      GNUNET_free(handle->oidc->scope);
-    if (NULL != handle->oidc->state)
-      GNUNET_free(handle->oidc->state);
-    if (NULL != handle->oidc->response)
-      json_decref(handle->oidc->response);
-    GNUNET_free(handle->oidc);
-  }
-  if ( NULL != handle->attr_list )
-  {
-    for (claim_entry = handle->attr_list->list_head;
-         NULL != claim_entry;)
+    GNUNET_free_non_null (handle->oidc->client_id);
+    GNUNET_free_non_null (handle->oidc->login_identity);
+    GNUNET_free_non_null (handle->oidc->nonce);
+    GNUNET_free_non_null (handle->oidc->redirect_uri);
+    GNUNET_free_non_null (handle->oidc->response_type);
+    GNUNET_free_non_null (handle->oidc->scope);
+    GNUNET_free_non_null (handle->oidc->state);
+    json_decref (handle->oidc->response);
+    GNUNET_free (handle->oidc);
+  }
+  if (NULL != handle->attr_list)
+  {
+    for (claim_entry = handle->attr_list->list_head; NULL != claim_entry;)
     {
       claim_tmp = claim_entry;
       claim_entry = claim_entry->next;
-      GNUNET_free(claim_tmp->claim);
-      GNUNET_free(claim_tmp);
+      GNUNET_free (claim_tmp->claim);
+      GNUNET_free (claim_tmp);
     }
     GNUNET_free (handle->attr_list);
   }
-  for (ego_entry = handle->ego_head;
-       NULL != ego_entry;)
+  for (ego_entry = handle->ego_head; NULL != ego_entry;)
   {
     ego_tmp = ego_entry;
     ego_entry = ego_entry->next;
@@ -512,10 +562,7 @@ cleanup_handle (struct RequestHandle *handle)
     GNUNET_free (ego_tmp->keystring);
     GNUNET_free (ego_tmp);
   }
-  if (NULL != handle->attr_it)
-  {
-    GNUNET_free(handle->attr_it);
-  }
+  GNUNET_free_non_null (handle->attr_it);
   GNUNET_free (handle);
 }
 
@@ -538,22 +585,21 @@ do_error (void *cls)
   struct MHD_Response *resp;
   char *json_error;
 
-  GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
+  GNUNET_asprintf (&json_error,
+                   "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
                    handle->emsg,
                    (NULL != handle->edesc) ? handle->edesc : "",
                    (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
                    (NULL != handle->oidc->state) ? handle->oidc->state : "",
                    (NULL != handle->oidc->state) ? "\"" : "");
-  if ( 0 == handle->response_code )
-  {
+  if (0 == handle->response_code)
     handle->response_code = MHD_HTTP_BAD_REQUEST;
-  }
   resp = GNUNET_REST_create_response (json_error);
   if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
-  {
-    MHD_add_response_header(resp, "WWW-Authenticate", "Basic");
-  }
-  MHD_add_response_header (resp, "Content-Type", "application/json");
+    MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Basic");
+  MHD_add_response_header (resp,
+                           MHD_HTTP_HEADER_CONTENT_TYPE,
+                           "application/json");
   handle->proc (handle->proc_cls, resp, handle->response_code);
   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
   GNUNET_free (json_error);
@@ -573,11 +619,12 @@ do_userinfo_error (void *cls)
   struct MHD_Response *resp;
   char *error;
 
-  GNUNET_asprintf (&error, "error=\"%s\", error_description=\"%s\"",
+  GNUNET_asprintf (&error,
+                   "error=\"%s\", error_description=\"%s\"",
                    handle->emsg,
                    (NULL != handle->edesc) ? handle->edesc : "");
   resp = GNUNET_REST_create_response ("");
-  MHD_add_response_header(resp, "WWW-Authenticate", error);
+  MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Bearer");
   handle->proc (handle->proc_cls, resp, handle->response_code);
   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
   GNUNET_free (error);
@@ -594,10 +641,12 @@ do_redirect_error (void *cls)
 {
   struct RequestHandle *handle = cls;
   struct MHD_Response *resp;
-  charredirect;
+  char *redirect;
   GNUNET_asprintf (&redirect,
                    "%s?error=%s&error_description=%s%s%s",
-                   handle->oidc->redirect_uri, handle->emsg, handle->edesc,
+                   handle->oidc->redirect_uri,
+                   handle->emsg,
+                   handle->edesc,
                    (NULL != handle->oidc->state) ? "&state=" : "",
                    (NULL != handle->oidc->state) ? handle->oidc->state : "");
   resp = GNUNET_REST_create_response ("");
@@ -629,7 +678,7 @@ do_timeout (void *cls)
 static void
 return_userinfo_response (void *cls)
 {
-  charresult_str;
+  char *result_str;
   struct RequestHandle *handle = cls;
   struct MHD_Response *resp;
 
@@ -641,23 +690,6 @@ return_userinfo_response (void *cls)
   cleanup_handle (handle);
 }
 
-/**
- * Returns base64 encoded string without padding
- *
- * @param string the string to encode
- * @return base64 encoded string
- */
-static char*
-base_64_encode(const char *s)
-{
-  char *enc;
-  char *tmp;
-
-  GNUNET_STRINGS_base64_encode(s, strlen(s), &enc);
-  tmp = strrchr (enc, '=');
-  *tmp = '\0';
-  return enc;
-}
 
 /**
  * Respond to OPTIONS request
@@ -668,22 +700,21 @@ base_64_encode(const char *s)
  */
 static void
 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
-              const charurl,
+              const char *url,
               void *cls)
 {
   struct MHD_Response *resp;
   struct RequestHandle *handle = cls;
 
-  //For now, independent of path return all options
+  // For now, independent of path return all options
   resp = GNUNET_REST_create_response (NULL);
-  MHD_add_response_header (resp,
-                           "Access-Control-Allow-Methods",
-                           allow_methods);
+  MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
   cleanup_handle (handle);
   return;
 }
 
+
 /**
  * Interprets cookie header and pass its identity keystring to handle
  */
@@ -694,64 +725,104 @@ cookie_identity_interpretation (struct RequestHandle *handle)
   char *cookies;
   struct GNUNET_TIME_Absolute current_time, *relog_time;
   char delimiter[] = "; ";
+  char *tmp_cookies;
+  char *token;
+  char *value;
 
-  //gets identity of login try with cookie
-  GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
+  // gets identity of login try with cookie
+  GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY,
+                      strlen (OIDC_COOKIE_HEADER_KEY),
                       &cache_key);
-  if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
-                                                             &cache_key) )
+  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
+                                                             ->header_param_map,
+                                                           &cache_key))
   {
-    //splits cookies and find 'Identity' cookie
-    cookies = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
-    handle->oidc->login_identity = strtok(cookies, delimiter);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No cookie found\n");
+    return;
+  }
+  // splits cookies and find 'Identity' cookie
+  tmp_cookies =
+    GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
+                                       &cache_key);
+  cookies = GNUNET_strdup (tmp_cookies);
+  token = strtok (cookies, delimiter);
+  handle->oidc->user_cancelled = GNUNET_NO;
+  handle->oidc->login_identity = NULL;
+  if (NULL == token)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unable to parse cookie: %s\n",
+                cookies);
+    GNUNET_free (cookies);
+    return;
+  }
 
-    while ( NULL != handle->oidc->login_identity )
-    {
-      if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
-      {
-        break;
-      }
-      handle->oidc->login_identity = strtok (NULL, delimiter);
-    }
-    GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity),
-                        &cache_key);
-    if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) )
-    {
-      relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
-                                                      &cache_key);
-      current_time = GNUNET_TIME_absolute_get ();
-      // 30 min after old login -> redirect to login
-      if ( current_time.abs_value_us <= relog_time->abs_value_us )
-      {
-        handle->oidc->login_identity = strtok(handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY);
-        handle->oidc->login_identity = GNUNET_strdup(handle->oidc->login_identity);
-      } else {
-        handle->oidc->login_identity = NULL;
-      }
-    }
-    else
+  while (NULL != token)
+  {
+    if (0 == strcmp (token, OIDC_COOKIE_HEADER_ACCESS_DENIED))
     {
-      handle->oidc->login_identity = NULL;
+      handle->oidc->user_cancelled = GNUNET_YES;
+      GNUNET_free (cookies);
+      return;
     }
+    if (NULL != strstr (token, OIDC_COOKIE_HEADER_INFORMATION_KEY))
+      break;
+    token = strtok (NULL, delimiter);
+  }
+  if (NULL == token)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "No cookie value to process: %s\n",
+                cookies);
+    GNUNET_free (cookies);
+    return;
+  }
+  GNUNET_CRYPTO_hash (token, strlen (token), &cache_key);
+  if (GNUNET_NO ==
+      GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
+  {
+    GNUNET_log (
+      GNUNET_ERROR_TYPE_WARNING,
+      "Found cookie `%s', but no corresponding expiration entry present...\n",
+      token);
+    GNUNET_free (cookies);
+    return;
+  }
+  relog_time =
+    GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
+  current_time = GNUNET_TIME_absolute_get ();
+  // 30 min after old login -> redirect to login
+  if (current_time.abs_value_us > relog_time->abs_value_us)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Found cookie `%s', but it is expired.\n",
+                token);
+    GNUNET_free (cookies);
+    return;
   }
+  value = strtok (token, OIDC_COOKIE_HEADER_INFORMATION_KEY);
+  GNUNET_assert (NULL != value);
+  handle->oidc->login_identity = GNUNET_strdup (value);
 }
 
 /**
  * Redirects to login page stored in configuration file
  */
 static void
-login_redirection(void *cls)
+login_redirect (void *cls)
 {
   char *login_base_url;
   char *new_redirect;
   struct MHD_Response *resp;
   struct RequestHandle *handle = cls;
 
-  if ( GNUNET_OK
-       == GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin",
-                                                 "address", &login_base_url) )
+  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
+                                                          "reclaim-rest-plugin",
+                                                          "address",
+                                                          &login_base_url))
   {
-    GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
+    GNUNET_asprintf (&new_redirect,
+                     "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
                      login_base_url,
                      OIDC_RESPONSE_TYPE_KEY,
                      handle->oidc->response_type,
@@ -767,18 +838,18 @@ login_redirection(void *cls)
                      (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "");
     resp = GNUNET_REST_create_response ("");
     MHD_add_response_header (resp, "Location", new_redirect);
-    GNUNET_free(login_base_url);
+    GNUNET_free (login_base_url);
   }
   else
   {
-    handle->emsg = GNUNET_strdup("server_error");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
     handle->edesc = GNUNET_strdup ("gnunet configuration failed");
     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
     return;
   }
   handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
-  GNUNET_free(new_redirect);
+  GNUNET_free (new_redirect);
   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
 }
 
@@ -789,165 +860,71 @@ static void
 oidc_iteration_error (void *cls)
 {
   struct RequestHandle *handle = cls;
-  handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR");
+  handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
   handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
   GNUNET_SCHEDULER_add_now (&do_error, handle);
 }
 
 
-static char*
-build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
-                  const struct GNUNET_RECLAIM_Ticket *ticket,
-                  const char* nonce)
-{
- char *ticket_str;
- json_t *code_json;
- char *signature_payload;
- char *signature_str;
- char *authz_code;
- size_t signature_payload_len;
- struct GNUNET_CRYPTO_EcdsaSignature signature;
- struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
-
- signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket);
- if (NULL != nonce)
-   signature_payload_len += strlen (nonce);
-
- signature_payload = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len);
- purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *)signature_payload;
- purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len);
- purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN);
- memcpy (&purpose[1],
-         ticket,
-         sizeof (struct GNUNET_RECLAIM_Ticket));
- if (NULL != nonce)
-   memcpy (&purpose[1] + sizeof (struct GNUNET_RECLAIM_Ticket),
-           nonce,
-           strlen (nonce));
- if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdsa_sign (issuer,
-                           purpose,
-                           &signature))
- {
-   GNUNET_free (signature_payload);
-   return NULL;
- }
- signature_str = GNUNET_STRINGS_data_to_string_alloc (&signature,
-                                                      sizeof (signature));
- ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket,
-                                                   sizeof (struct GNUNET_RECLAIM_Ticket));
-
- code_json = json_object ();
- json_object_set_new (code_json,
-                      "ticket",
-                      json_string (ticket_str));
- if (NULL != nonce)
-   json_object_set_new (code_json,
-                        "nonce",
-                        json_string (nonce));
- json_object_set_new (code_json,
-                      "signature",
-                      json_string (signature_str));
- authz_code = json_dumps (code_json,
-                          JSON_INDENT(0) | JSON_COMPACT);
- GNUNET_free (signature_payload);
- GNUNET_free (signature_str);
- GNUNET_free (ticket_str);
- json_decref (code_json);
- return authz_code;
-}
-
-
+/**
+ * Issues ticket and redirects to relying party with the authorization code as
+ * parameter. Otherwise redirects with error
+ */
 static void
-get_client_name_result (void *cls,
-                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
-                        const char *label,
-                        unsigned int rd_count,
-                        const struct GNUNET_GNSRECORD_Data *rd)
+oidc_ticket_issue_cb (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
 {
   struct RequestHandle *handle = cls;
   struct MHD_Response *resp;
   char *ticket_str;
   char *redirect_uri;
-  char *code_json_string;
-  char *code_base64_final_string;
-  char *redirect_path;
-  char *tmp;
-  char *tmp_prefix;
-  char *prefix;
-  ticket_str = GNUNET_STRINGS_data_to_string_alloc (&handle->ticket,
-                                                    sizeof (struct GNUNET_RECLAIM_Ticket));
-  //TODO add signature to code payload over nonce and ticket _and_ use jansson here!
-  //TODO change if more attributes are needed (see max_age)
-  code_json_string = build_authz_code (&handle->priv_key,
+  char *code_string;
+
+  handle->idp_op = NULL;
+  handle->ticket = *ticket;
+  if (NULL == ticket)
+  {
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
+    handle->edesc = GNUNET_strdup ("Server cannot generate ticket.");
+    GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+    return;
+  }
+  ticket_str =
+    GNUNET_STRINGS_data_to_string_alloc (&handle->ticket,
+                                         sizeof (struct GNUNET_RECLAIM_Ticket));
+  // TODO change if more attributes are needed (see max_age)
+  code_string = OIDC_build_authz_code (&handle->priv_key,
                                        &handle->ticket,
+                                       handle->attr_list,
                                        handle->oidc->nonce);
-  /*GNUNET_asprintf (&code_json_string, "{\"ticket\":\"%s\"%s%s%s}",
-                   ticket_str,
-                   (NULL != handle->oidc->nonce) ? ", \"nonce\":\"" : "",
-                   (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "",
-                   (NULL != handle->oidc->nonce) ? "\"" : "");*/
-  code_base64_final_string = base_64_encode(code_json_string);
-  tmp = GNUNET_strdup (handle->oidc->redirect_uri);
-  redirect_path = strtok (tmp, "/");
-  redirect_path = strtok (NULL, "/");
-  redirect_path = strtok (NULL, "/");
-  tmp_prefix = GNUNET_strdup (handle->oidc->redirect_uri);
-  prefix = strrchr (tmp_prefix,
-                    (unsigned char) '.');
-  *prefix = '\0';
-  GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s",
-                   tmp_prefix,
-                   handle->tld,
-                   redirect_path,
-                   handle->oidc->response_type,
-                   code_base64_final_string, handle->oidc->state);
+  if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) &&
+      (NULL != handle->tld))
+  {
+
+    GNUNET_asprintf (&redirect_uri,
+                     "%s.%s/%s?%s=%s&state=%s",
+                     handle->redirect_prefix,
+                     handle->tld,
+                     handle->redirect_suffix,
+                     handle->oidc->response_type,
+                     code_string,
+                     handle->oidc->state);
+  }
+  else
+  {
+    GNUNET_asprintf (&redirect_uri,
+                     "%s?%s=%s&state=%s",
+                     handle->oidc->redirect_uri,
+                     handle->oidc->response_type,
+                     code_string,
+                     handle->oidc->state);
+  }
   resp = GNUNET_REST_create_response ("");
   MHD_add_response_header (resp, "Location", redirect_uri);
   handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
-  GNUNET_free (tmp);
-  GNUNET_free (tmp_prefix);
   GNUNET_free (redirect_uri);
   GNUNET_free (ticket_str);
-  GNUNET_free (code_json_string);
-  GNUNET_free (code_base64_final_string);
-  return;
-}
-
-static void
-get_client_name_error (void *cls)
-{
-  struct RequestHandle *handle = cls;
-
-  handle->emsg = GNUNET_strdup("server_error");
-  handle->edesc = GNUNET_strdup("Server cannot generate ticket, no name found for client.");
-  GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
-}
-
-/**
- * Issues ticket and redirects to relying party with the authorization code as
- * parameter. Otherwise redirects with error
- */
-static void
-oidc_ticket_issue_cb (void* cls,
-                      const struct GNUNET_RECLAIM_Ticket *ticket)
-{
-  struct RequestHandle *handle = cls;
-  handle->idp_op = NULL;
-  handle->ticket = *ticket;
-  if (NULL != ticket) {
-    GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle,
-                                   &handle->priv_key,
-                                   &handle->oidc->client_pkey,
-                                   &get_client_name_error,
-                                   handle,
-                                   &get_client_name_result,
-                                   handle);
-    return;
-  }
-  handle->emsg = GNUNET_strdup("server_error");
-  handle->edesc = GNUNET_strdup("Server cannot generate ticket.");
-  GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+  GNUNET_free (code_string);
 }
 
 static void
@@ -958,8 +935,8 @@ oidc_collect_finished_cb (void *cls)
   handle->ticket_it = NULL;
   if (NULL == handle->attr_list->list_head)
   {
-    handle->emsg = GNUNET_strdup("invalid_scope");
-    handle->edesc = GNUNET_strdup("The requested scope is not available.");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE);
+    handle->edesc = GNUNET_strdup ("The requested scope is not available.");
     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
     return;
   }
@@ -982,39 +959,40 @@ oidc_attr_collect (void *cls,
 {
   struct RequestHandle *handle = cls;
   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
-  charscope_variables;
-  charscope_variable;
-  char delimiter[]=" ";
+  char *scope_variables;
+  char *scope_variable;
+  char delimiter[] = " ";
 
-  if ( (NULL == attr->name) || (NULL == attr->data) )
+  if ((NULL == attr->name) || (NULL == attr->data))
   {
     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
     return;
   }
 
-  scope_variables = GNUNET_strdup(handle->oidc->scope);
+  scope_variables = GNUNET_strdup (handle->oidc->scope);
   scope_variable = strtok (scope_variables, delimiter);
   while (NULL != scope_variable)
   {
-    if ( 0 == strcmp (attr->name, scope_variable) )
-    {
+    if (0 == strcmp (attr->name, scope_variable))
       break;
-    }
     scope_variable = strtok (NULL, delimiter);
   }
-  if ( NULL == scope_variable )
+  if (NULL == scope_variable)
   {
     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
-    GNUNET_free(scope_variables);
+    GNUNET_free (scope_variables);
     return;
   }
-  GNUNET_free(scope_variables);
+  GNUNET_free (scope_variables);
 
-  le = GNUNET_new(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
-  le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name, attr->type,
-                                                  attr->data, attr->data_size);
-  GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head,
-                              handle->attr_list->list_tail, le);
+  le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
+  le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name,
+                                                  attr->type,
+                                                  attr->data,
+                                                  attr->data_size);
+  GNUNET_CONTAINER_DLL_insert (handle->attr_list->list_head,
+                               handle->attr_list->list_tail,
+                               le);
   GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
 }
 
@@ -1023,70 +1001,215 @@ oidc_attr_collect (void *cls,
  * Checks time and cookie and redirects accordingly
  */
 static void
-login_check (void *cls)
+code_redirect (void *cls)
 {
   struct RequestHandle *handle = cls;
-  struct GNUNET_TIME_Absolute current_time, *relog_time;
-  struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey;
+  struct GNUNET_TIME_Absolute current_time;
+  struct GNUNET_TIME_Absolute *relog_time;
+  struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
+  struct GNUNET_CRYPTO_EcdsaPublicKey ego_pkey;
   struct GNUNET_HashCode cache_key;
   char *identity_cookie;
 
-  GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity);
+  GNUNET_asprintf (&identity_cookie,
+                   "Identity=%s",
+                   handle->oidc->login_identity);
   GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
-  GNUNET_free(identity_cookie);
-  //No login time for identity -> redirect to login
-  if ( GNUNET_YES
-       == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time,
-                                                  &cache_key) )
-  {
-    relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
-                                                    &cache_key);
+  GNUNET_free (identity_cookie);
+  // No login time for identity -> redirect to login
+  if (GNUNET_YES ==
+      GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key))
+  {
+    relog_time =
+      GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
     current_time = GNUNET_TIME_absolute_get ();
     // 30 min after old login -> redirect to login
-    if ( current_time.abs_value_us <= relog_time->abs_value_us )
+    if (current_time.abs_value_us <= relog_time->abs_value_us)
     {
-      if ( GNUNET_OK
-           != GNUNET_CRYPTO_ecdsa_public_key_from_string (
-                                                          handle->oidc->login_identity,
-                                                          strlen (handle->oidc->login_identity), &pubkey) )
+      if (GNUNET_OK !=
+          GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc
+                                                        ->login_identity,
+                                                      strlen (
+                                                        handle->oidc
+                                                          ->login_identity),
+                                                      &pubkey))
       {
-        handle->emsg = GNUNET_strdup("invalid_cookie");
-        handle->edesc = GNUNET_strdup(
-                                      "The cookie of a login identity is not valid");
+        handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_COOKIE);
+        handle->edesc =
+          GNUNET_strdup ("The cookie of a login identity is not valid");
         GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
         return;
       }
       // iterate over egos and compare their public key
-      for (handle->ego_entry = handle->ego_head;
-           NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
+      for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry;
+           handle->ego_entry = handle->ego_entry->next)
       {
         GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
-        if ( 0
-             == memcmp (&ego_pkey, &pubkey,
-                        sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
+        if (0 == GNUNET_memcmp (&ego_pkey, &pubkey))
         {
-          handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (
-                                                                   handle->ego_entry->ego);
-          handle->resp_object = GNUNET_JSONAPI_document_new ();
+          handle->priv_key =
+            *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
           handle->idp = GNUNET_RECLAIM_connect (cfg);
-          handle->attr_list = GNUNET_new(
-                                         struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
-          handle->attr_it = GNUNET_RECLAIM_get_attributes_start (
-                                                                 handle->idp, &handle->priv_key, &oidc_iteration_error, handle,
-                                                                 &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle);
+          handle->attr_list =
+            GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
+          handle->attr_it =
+            GNUNET_RECLAIM_get_attributes_start (handle->idp,
+                                                 &handle->priv_key,
+                                                 &oidc_iteration_error,
+                                                 handle,
+                                                 &oidc_attr_collect,
+                                                 handle,
+                                                 &oidc_collect_finished_cb,
+                                                 handle);
           return;
         }
       }
-      //handle->emsg = GNUNET_strdup("invalid_cookie");
-      //handle->edesc = GNUNET_strdup(
-      //                              "The cookie of the login identity is not valid");
-      //GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
-      GNUNET_SCHEDULER_add_now (&login_redirection,handle);
+      GNUNET_SCHEDULER_add_now (&login_redirect, handle);
       return;
     }
   }
 }
 
+
+static void
+build_redirect (void *cls)
+{
+  struct RequestHandle *handle = cls;
+  struct MHD_Response *resp;
+  char *redirect_uri;
+
+  if (GNUNET_YES == handle->oidc->user_cancelled)
+  {
+    if ((NULL != handle->redirect_prefix) &&
+        (NULL != handle->redirect_suffix) && (NULL != handle->tld))
+    {
+      GNUNET_asprintf (&redirect_uri,
+                       "%s.%s/%s?error=%s&error_description=%s&state=%s",
+                       handle->redirect_prefix,
+                       handle->tld,
+                       handle->redirect_suffix,
+                       "access_denied",
+                       "User denied access",
+                       handle->oidc->state);
+    }
+    else
+    {
+      GNUNET_asprintf (&redirect_uri,
+                       "%s?error=%s&error_description=%s&state=%s",
+                       handle->oidc->redirect_uri,
+                       "access_denied",
+                       "User denied access",
+                       handle->oidc->state);
+    }
+    resp = GNUNET_REST_create_response ("");
+    MHD_add_response_header (resp, "Location", redirect_uri);
+    handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
+    GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
+    GNUNET_free (redirect_uri);
+    return;
+  }
+  GNUNET_SCHEDULER_add_now (&code_redirect, handle);
+}
+
+
+static void
+lookup_redirect_uri_result (void *cls,
+                            uint32_t rd_count,
+                            const struct GNUNET_GNSRECORD_Data *rd)
+{
+  struct RequestHandle *handle = cls;
+  char *tmp;
+  char *tmp_key_str;
+  char *pos;
+  struct GNUNET_CRYPTO_EcdsaPublicKey redirect_zone;
+
+  handle->gns_op = NULL;
+  if (0 == rd_count)
+  {
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
+    handle->edesc =
+      GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
+    GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+    return;
+  }
+  for (int i = 0; i < rd_count; i++)
+  {
+    if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type)
+      continue;
+    if (0 != strncmp (rd[i].data, handle->oidc->redirect_uri, rd[i].data_size))
+      continue;
+    tmp = GNUNET_strndup (rd[i].data, rd[i].data_size);
+    if (NULL == strstr (tmp, handle->oidc->client_id))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Redirect uri %s does not contain client_id %s",
+                  tmp,
+                  handle->oidc->client_id);
+    }
+    else
+    {
+
+      pos = strrchr (tmp, (unsigned char) '.');
+      *pos = '\0';
+      handle->redirect_prefix = GNUNET_strdup (tmp);
+      tmp_key_str = pos + 1;
+      pos = strchr (tmp_key_str, (unsigned char) '/');
+      *pos = '\0';
+      handle->redirect_suffix = GNUNET_strdup (pos + 1);
+
+      GNUNET_STRINGS_string_to_data (tmp_key_str,
+                                     strlen (tmp_key_str),
+                                     &redirect_zone,
+                                     sizeof (redirect_zone));
+    }
+    GNUNET_SCHEDULER_add_now (&build_redirect, handle);
+    GNUNET_free (tmp);
+    return;
+  }
+  handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
+  handle->edesc =
+    GNUNET_strdup ("Server cannot generate ticket, redirect uri not found.");
+  GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+}
+
+
+/**
+ * Initiate redirect back to client.
+ */
+static void
+client_redirect (void *cls)
+{
+  struct RequestHandle *handle = cls;
+
+  /* Lookup client redirect uri to verify request */
+  handle->gns_op =
+    GNUNET_GNS_lookup (handle->gns_handle,
+                       GNUNET_GNS_EMPTY_LABEL_AT,
+                       &handle->oidc->client_pkey,
+                       GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT,
+                       GNUNET_GNS_LO_DEFAULT,
+                       &lookup_redirect_uri_result,
+                       handle);
+}
+
+static char *
+get_url_parameter_copy (const struct RequestHandle *handle, const char *key)
+{
+  struct GNUNET_HashCode hc;
+  char *value;
+  GNUNET_CRYPTO_hash (key, strlen (key), &hc);
+  if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
+                                                              ->url_param_map,
+                                                            &hc))
+    return NULL;
+  value =
+    GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, &hc);
+  if (NULL == value)
+    return NULL;
+  return GNUNET_strdup (value);
+}
+
+
 /**
  * Iteration over all results finished, build final
  * response.
@@ -1100,122 +1223,123 @@ build_authz_response (void *cls)
   struct GNUNET_HashCode cache_key;
 
   char *expected_scope;
-  char delimiter[]=" ";
+  char delimiter[] = " ";
   int number_of_ignored_parameter, iterator;
 
 
   // REQUIRED value: redirect_uri
-  GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
-                      &cache_key);
-  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
-                                                           &cache_key))
+  handle->oidc->redirect_uri =
+    get_url_parameter_copy (handle, OIDC_REDIRECT_URI_KEY);
+  if (NULL == handle->oidc->redirect_uri)
   {
-    handle->emsg=GNUNET_strdup("invalid_request");
-    handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
+    handle->edesc = GNUNET_strdup ("missing parameter redirect_uri");
     GNUNET_SCHEDULER_add_now (&do_error, handle);
     return;
   }
-  handle->oidc->redirect_uri = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
-                                                                                &cache_key));
 
   // REQUIRED value: response_type
-  GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
-                      &cache_key);
-  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
-                                                           &cache_key))
+  handle->oidc->response_type =
+    get_url_parameter_copy (handle, OIDC_RESPONSE_TYPE_KEY);
+  if (NULL == handle->oidc->response_type)
   {
-    handle->emsg=GNUNET_strdup("invalid_request");
-    handle->edesc=GNUNET_strdup("missing parameter response_type");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
+    handle->edesc = GNUNET_strdup ("missing parameter response_type");
     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
     return;
   }
-  handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
-                                                                  &cache_key);
-  handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
 
   // REQUIRED value: scope
-  GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
-  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
-                                                           &cache_key))
+  handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY);
+  if (NULL == handle->oidc->scope)
   {
-    handle->emsg=GNUNET_strdup("invalid_request");
-    handle->edesc=GNUNET_strdup("missing parameter scope");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE);
+    handle->edesc = GNUNET_strdup ("missing parameter scope");
     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
     return;
   }
-  handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
-                                                          &cache_key);
-  handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
 
-  //OPTIONAL value: nonce
-  GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
-  if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
-                                                            &cache_key))
-  {
-    handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
-                                                            &cache_key);
-    handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
-  }
+  // OPTIONAL value: nonce
+  handle->oidc->nonce = get_url_parameter_copy (handle, OIDC_NONCE_KEY);
 
-  //TODO check other values if needed
-  number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
-  for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
+  // TODO check other values if needed
+  number_of_ignored_parameter =
+    sizeof (OIDC_ignored_parameter_array) / sizeof (char *);
+  for (iterator = 0; iterator < number_of_ignored_parameter; iterator++)
   {
     GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
-                        strlen(OIDC_ignored_parameter_array[iterator]),
+                        strlen (OIDC_ignored_parameter_array[iterator]),
                         &cache_key);
-    if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
-                                                            &cache_key))
+    if (GNUNET_YES ==
+        GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
+                                                  ->url_param_map,
+                                                &cache_key))
     {
-      handle->emsg=GNUNET_strdup("access_denied");
-      GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
+      handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_ACCESS_DENIED);
+      GNUNET_asprintf (&handle->edesc,
+                       "Server will not handle parameter: %s",
                        OIDC_ignored_parameter_array[iterator]);
       GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
       return;
     }
   }
 
-  // Checks if response_type is 'code'
-  if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
+  // We only support authorization code flows.
+  if (0 != strcmp (handle->oidc->response_type,
+                   OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE))
   {
-    handle->emsg=GNUNET_strdup("unsupported_response_type");
-    handle->edesc=GNUNET_strdup("The authorization server does not support "
-                                "obtaining this authorization code.");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE);
+    handle->edesc = GNUNET_strdup ("The authorization server does not support "
+                                   "obtaining this authorization code.");
     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
     return;
   }
 
   // Checks if scope contains 'openid'
-  expected_scope = GNUNET_strdup(handle->oidc->scope);
-  chartest;
+  expected_scope = GNUNET_strdup (handle->oidc->scope);
+  char *test;
   test = strtok (expected_scope, delimiter);
   while (NULL != test)
   {
-    if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
-    {
+    if (0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope))
       break;
-    }
     test = strtok (NULL, delimiter);
   }
   if (NULL == test)
   {
-    handle->emsg = GNUNET_strdup("invalid_scope");
-    handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
-                                "malformed.");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE);
+    handle->edesc =
+      GNUNET_strdup ("The requested scope is invalid, unknown, or malformed.");
     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
-    GNUNET_free(expected_scope);
+    GNUNET_free (expected_scope);
     return;
   }
 
-  GNUNET_free(expected_scope);
+  GNUNET_free (expected_scope);
+  if ((NULL == handle->oidc->login_identity) &&
+      (GNUNET_NO == handle->oidc->user_cancelled))
+    GNUNET_SCHEDULER_add_now (&login_redirect, handle);
+  else
+    GNUNET_SCHEDULER_add_now (&client_redirect, handle);
+}
+
+/**
+ * Iterate over tlds in config
+ */
+static void
+tld_iter (void *cls, const char *section, const char *option, const char *value)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
 
-  if( NULL != handle->oidc->login_identity )
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_ecdsa_public_key_from_string (value, strlen (value), &pkey))
   {
-    GNUNET_SCHEDULER_add_now(&login_check,handle);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping non key %s\n", value);
     return;
   }
-
-  GNUNET_SCHEDULER_add_now(&login_redirection,handle);
+  if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
+    handle->tld = GNUNET_strdup (option + 1);
 }
 
 /**
@@ -1227,59 +1351,47 @@ build_authz_response (void *cls)
  */
 static void
 authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
-                    const charurl,
+                    const char *url,
                     void *cls)
 {
   struct RequestHandle *handle = cls;
-  struct GNUNET_HashCode cache_key;
   struct EgoEntry *tmp_ego;
   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
 
-  cookie_identity_interpretation(handle);
+  cookie_identity_interpretation (handle);
 
-  //RECOMMENDED value: state - REQUIRED for answers
-  GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
-  if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
-                                                            &cache_key))
-  {
-    handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
-                                                            &cache_key);
-    handle->oidc->state = GNUNET_strdup (handle->oidc->state);
-  }
+  // RECOMMENDED value: state - REQUIRED for answers
+  handle->oidc->state = get_url_parameter_copy (handle, OIDC_STATE_KEY);
 
   // REQUIRED value: client_id
-  GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
-                      &cache_key);
-  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
-                                                           &cache_key))
+  handle->oidc->client_id = get_url_parameter_copy (handle, OIDC_CLIENT_ID_KEY);
+  if (NULL == handle->oidc->client_id)
   {
-    handle->emsg=GNUNET_strdup("invalid_request");
-    handle->edesc=GNUNET_strdup("missing parameter client_id");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
+    handle->edesc = GNUNET_strdup ("missing parameter client_id");
     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
     return;
   }
-  handle->oidc->client_id = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
-                                                                             &cache_key));
 
-  if ( GNUNET_OK
-       != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
-                                                      strlen (handle->oidc->client_id),
-                                                      &handle->oidc->client_pkey) )
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
+                                                  strlen (
+                                                    handle->oidc->client_id),
+                                                  &handle->oidc->client_pkey))
   {
-    handle->emsg = GNUNET_strdup("unauthorized_client");
-    handle->edesc = GNUNET_strdup("The client is not authorized to request an "
-                                  "authorization code using this method.");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT);
+    handle->edesc = GNUNET_strdup ("The client is not authorized to request an "
+                                   "authorization code using this method.");
     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
     return;
   }
 
-
-  if ( NULL == handle->ego_head )
+  if (NULL == handle->ego_head)
   {
-    handle->emsg = GNUNET_strdup("server_error");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
     handle->edesc = GNUNET_strdup ("Egos are missing");
     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
@@ -1287,21 +1399,24 @@ authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
   }
 
   handle->ego_entry = handle->ego_head;
-  handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
-  //If we know this identity, translated the corresponding TLD
-  //TODO: We might want to have a reverse lookup functionality for TLDs?
+  handle->priv_key =
+    *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
+  // If we know this identity, translated the corresponding TLD
+  // TODO: We might want to have a reverse lookup functionality for TLDs?
   for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next)
   {
     priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego);
-    GNUNET_CRYPTO_ecdsa_key_get_public (priv_key,
-                                        &pkey);
-    if ( 0 == memcmp (&pkey, &handle->oidc->client_pkey,
-                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
+    GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, &pkey);
+    if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey))
     {
       handle->tld = GNUNET_strdup (tmp_ego->identifier);
       handle->ego_entry = handle->ego_tail;
     }
-  } 
+  }
+  if (NULL == handle->tld)
+    GNUNET_CONFIGURATION_iterate_section_values (cfg, "gns", tld_iter, handle);
+  if (NULL == handle->tld)
+    handle->tld = GNUNET_strdup (handle->oidc->client_id);
   GNUNET_SCHEDULER_add_now (&build_authz_response, handle);
 }
 
@@ -1314,7 +1429,7 @@ authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
  */
 static void
 login_cont (struct GNUNET_REST_RequestHandle *con_handle,
-            const charurl,
+            const char *url,
             void *cls)
 {
   struct MHD_Response *resp = GNUNET_REST_create_response ("");
@@ -1322,181 +1437,249 @@ login_cont (struct GNUNET_REST_RequestHandle *con_handle,
   struct GNUNET_HashCode cache_key;
   struct GNUNET_TIME_Absolute *current_time;
   struct GNUNET_TIME_Absolute *last_time;
-  char* cookie;
+  char *cookie;
+  char *header_val;
   json_t *root;
   json_error_t error;
   json_t *identity;
-  char term_data[handle->rest_handle->data_size+1];
+  char term_data[handle->rest_handle->data_size + 1];
   term_data[handle->rest_handle->data_size] = '\0';
-  GNUNET_memcpy (term_data, handle->rest_handle->data, handle->rest_handle->data_size);
+  GNUNET_memcpy (term_data,
+                 handle->rest_handle->data,
+                 handle->rest_handle->data_size);
   root = json_loads (term_data, JSON_DECODE_ANY, &error);
   identity = json_object_get (root, "identity");
-  if ( json_is_string(identity) )
+  if (! json_is_string (identity))
   {
-    GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
-    MHD_add_response_header (resp, "Set-Cookie", cookie);
-    MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST");
-    GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Error parsing json string from %s\n",
+                term_data);
+    handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
+    json_decref (root);
+    GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
+    return;
+  }
+  GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
+  GNUNET_asprintf (&header_val,
+                   "%s;Max-Age=%d",
+                   cookie,
+                   OIDC_COOKIE_EXPIRATION);
+  MHD_add_response_header (resp, "Set-Cookie", header_val);
+  MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST");
+  GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
 
-    current_time = GNUNET_new(struct GNUNET_TIME_Absolute);
+  if (0 != strcmp (json_string_value (identity), "Denied"))
+  {
+    current_time = GNUNET_new (struct GNUNET_TIME_Absolute);
     *current_time = GNUNET_TIME_relative_to_absolute (
-                                                      GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (),
-                                                                                     5));
-    last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key);
-    if (NULL != last_time)
-    {
-      GNUNET_free(last_time);
-    }
-    GNUNET_CONTAINER_multihashmap_put (
-                                       OIDC_identity_login_time, &cache_key, current_time,
+      GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (),
+                                     OIDC_COOKIE_EXPIRATION));
+    last_time =
+      GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key);
+    GNUNET_free_non_null (last_time);
+    GNUNET_CONTAINER_multihashmap_put (OIDC_cookie_jar_map,
+                                       &cache_key,
+                                       current_time,
                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
-
-    handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
-    GNUNET_free(cookie);
-  }
-  else
-  {
-    handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
   }
+  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+  GNUNET_free (cookie);
+  GNUNET_free (header_val);
   json_decref (root);
   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
-  return;
 }
 
-/**
- * Responds to token url-encoded POST request
- *
- * @param con_handle the connection handle
- * @param url the url
- * @param cls the RequestHandle
- */
-static void
-token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
-                const char* url,
-                void *cls)
+static int
+check_authorization (struct RequestHandle *handle,
+                     struct GNUNET_CRYPTO_EcdsaPublicKey *cid)
 {
-  //TODO static strings
-  struct RequestHandle *handle = cls;
   struct GNUNET_HashCode cache_key;
-  char *authorization, *credentials;
-  char delimiter[]=" ";
-  char delimiter_user_psw[]=":";
-  char *grant_type, *code;
-  char *user_psw = NULL, *client_id, *psw;
-  char *expected_psw;
-  int client_exists = GNUNET_NO;
-  struct MHD_Response *resp;
-  char* code_output;
-  json_t *root;
-  json_t *ticket_string;
-  json_t *nonce;
-  json_error_t error;
-  char *json_response;
-  char *jwt_secret;
+  char *authorization;
+  char *credentials;
+  char *basic_authorization;
+  char *client_id;
+  char *pass;
+  char *expected_pass;
 
-  /*
-   * Check Authorization
-   */
   GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
                       strlen (OIDC_AUTHORIZATION_HEADER_KEY),
                       &cache_key);
-  if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
-                                                            &cache_key) )
+  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
+                                                             ->header_param_map,
+                                                           &cache_key))
   {
-    handle->emsg=GNUNET_strdup("invalid_client");
-    handle->edesc=GNUNET_strdup("missing authorization");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
+    handle->edesc = GNUNET_strdup ("missing authorization");
     handle->response_code = MHD_HTTP_UNAUTHORIZED;
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
-    return;
+    return GNUNET_SYSERR;
   }
-  authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
+  authorization =
+    GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
+                                       &cache_key);
 
-  //split header in "Basic" and [content]
-  credentials = strtok (authorization, delimiter);
-  if (0 != strcmp ("Basic",credentials))
+  // split header in "Basic" and [content]
+  credentials = strtok (authorization, " ");
+  if (0 != strcmp ("Basic", credentials))
   {
-    handle->emsg=GNUNET_strdup("invalid_client");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
     handle->response_code = MHD_HTTP_UNAUTHORIZED;
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
-    return;
+    return GNUNET_SYSERR;
   }
-  credentials = strtok(NULL, delimiter);
+  credentials = strtok (NULL, " ");
   if (NULL == credentials)
   {
-    handle->emsg=GNUNET_strdup("invalid_client");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
     handle->response_code = MHD_HTTP_UNAUTHORIZED;
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
-    return;
+    return GNUNET_SYSERR;
   }
-  GNUNET_STRINGS_base64_decode (credentials, strlen (credentials), (void**)&user_psw);
+  GNUNET_STRINGS_base64_decode (credentials,
+                                strlen (credentials),
+                                (void **) &basic_authorization);
 
-  if ( NULL == user_psw )
+  if (NULL == basic_authorization)
   {
-    handle->emsg=GNUNET_strdup("invalid_client");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
     handle->response_code = MHD_HTTP_UNAUTHORIZED;
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
-    return;
+    return GNUNET_SYSERR;
   }
-  client_id = strtok (user_psw, delimiter_user_psw);
-  if ( NULL == client_id )
+  client_id = strtok (basic_authorization, ":");
+  if (NULL == client_id)
   {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg=GNUNET_strdup("invalid_client");
+    GNUNET_free_non_null (basic_authorization);
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
     handle->response_code = MHD_HTTP_UNAUTHORIZED;
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
-    return;
+    return GNUNET_SYSERR;
   }
-  psw = strtok (NULL, delimiter_user_psw);
-  if (NULL == psw)
+  pass = strtok (NULL, ":");
+  if (NULL == pass)
   {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg=GNUNET_strdup("invalid_client");
+    GNUNET_free_non_null (basic_authorization);
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
     handle->response_code = MHD_HTTP_UNAUTHORIZED;
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
-    return;
+    return GNUNET_SYSERR;
   }
 
-  //check client password
-  if ( GNUNET_OK
-       == GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin",
-                                                 "psw", &expected_psw) )
+  // check client password
+  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
+                                                          "reclaim-rest-plugin",
+                                                          "OIDC_CLIENT_SECRET",
+                                                          &expected_pass))
   {
-    if (0 != strcmp (expected_psw, psw))
+    if (0 != strcmp (expected_pass, pass))
     {
-      GNUNET_free_non_null(user_psw);
-      GNUNET_free(expected_psw);
-      handle->emsg=GNUNET_strdup("invalid_client");
+      GNUNET_free_non_null (basic_authorization);
+      GNUNET_free (expected_pass);
+      handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
       handle->response_code = MHD_HTTP_UNAUTHORIZED;
-      GNUNET_SCHEDULER_add_now (&do_error, handle);
-      return;
+      return GNUNET_SYSERR;
     }
-    GNUNET_free(expected_psw);
+    GNUNET_free (expected_pass);
   }
   else
   {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg = GNUNET_strdup("server_error");
+    GNUNET_free_non_null (basic_authorization);
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
     handle->edesc = GNUNET_strdup ("gnunet configuration failed");
     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
-    return;
+    return GNUNET_SYSERR;
   }
 
-  //check client_id
-  for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; )
+  // check client_id
+  for (handle->ego_entry = handle->ego_head;
+       NULL != handle->ego_entry;
+       handle->ego_entry = handle->ego_entry->next)
   {
-    if ( 0 == strcmp(handle->ego_entry->keystring, client_id))
-    {
-      client_exists = GNUNET_YES;
+    if (0 == strcmp (handle->ego_entry->keystring, client_id))
       break;
-    }
-    handle->ego_entry = handle->ego_entry->next;
   }
-  if (GNUNET_NO == client_exists)
+  if (NULL == handle->ego_entry)
   {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg=GNUNET_strdup("invalid_client");
+    GNUNET_free_non_null (basic_authorization);
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT);
     handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    return GNUNET_SYSERR;
+  }
+  GNUNET_STRINGS_string_to_data (client_id,
+                                 strlen (client_id),
+                                 cid,
+                                 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+
+  GNUNET_free (basic_authorization);
+  return GNUNET_OK;
+}
+
+static int
+ego_exists (struct RequestHandle *handle,
+            struct GNUNET_CRYPTO_EcdsaPublicKey *test_key)
+{
+  struct EgoEntry *ego_entry;
+  struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
+
+  for (ego_entry = handle->ego_head; NULL != ego_entry;
+       ego_entry = ego_entry->next)
+  {
+    GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
+    if (0 == GNUNET_memcmp (&pub_key, test_key))
+      break;
+  }
+  if (NULL == ego_entry)
+    return GNUNET_NO;
+  return GNUNET_YES;
+}
+
+static void
+persist_access_token (const struct RequestHandle *handle,
+                      const char *access_token,
+                      const struct GNUNET_RECLAIM_Ticket *ticket)
+{
+  struct GNUNET_HashCode hc;
+  struct GNUNET_RECLAIM_Ticket *ticketbuf;
+
+  GNUNET_CRYPTO_hash (access_token, strlen (access_token), &hc);
+  ticketbuf = GNUNET_new (struct GNUNET_RECLAIM_Ticket);
+  *ticketbuf = *ticket;
+  GNUNET_CONTAINER_multihashmap_put (
+    OIDC_access_token_map,
+    &hc,
+    ticketbuf,
+    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+}
+
+/**
+ * Responds to token url-encoded POST request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+static void
+token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
+                const char *url,
+                void *cls)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_TIME_Relative expiration_time;
+  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *cl;
+  struct GNUNET_RECLAIM_Ticket ticket;
+  struct GNUNET_CRYPTO_EcdsaPublicKey cid;
+  struct GNUNET_HashCode cache_key;
+  struct MHD_Response *resp;
+  char *grant_type;
+  char *code;
+  char *json_response;
+  char *id_token;
+  char *access_token;
+  char *jwt_secret;
+  char *nonce;
+  int i = 1;
+
+  /*
+   * Check Authorization
+   */
+  if (GNUNET_SYSERR == check_authorization (handle, &cid))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "OIDC authorization for token endpoint failed\n");
     GNUNET_SCHEDULER_add_now (&do_error, handle);
     return;
   }
@@ -1505,32 +1688,33 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
    * Check parameter
    */
 
-  //TODO Do not allow multiple equal parameter names
-  //REQUIRED grant_type
-  GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key);
-  if ( GNUNET_NO
-       == GNUNET_CONTAINER_multihashmap_contains (
-                                                  handle->rest_handle->url_param_map, &cache_key) )
+  // TODO Do not allow multiple equal parameter names
+  // REQUIRED grant_type
+  GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY,
+                      strlen (OIDC_GRANT_TYPE_KEY),
+                      &cache_key);
+  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
+                                                             ->url_param_map,
+                                                           &cache_key))
   {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg = GNUNET_strdup("invalid_request");
-    handle->edesc = GNUNET_strdup("missing parameter grant_type");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
+    handle->edesc = GNUNET_strdup ("missing parameter grant_type");
     handle->response_code = MHD_HTTP_BAD_REQUEST;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
     return;
   }
-  grant_type = GNUNET_CONTAINER_multihashmap_get (
-                                                  handle->rest_handle->url_param_map, &cache_key);
+  grant_type =
+    GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
+                                       &cache_key);
 
-  //REQUIRED code
+  // REQUIRED code
   GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key);
-  if ( GNUNET_NO
-       == GNUNET_CONTAINER_multihashmap_contains (
-                                                  handle->rest_handle->url_param_map, &cache_key) )
+  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
+                                                             ->url_param_map,
+                                                           &cache_key))
   {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg = GNUNET_strdup("invalid_request");
-    handle->edesc = GNUNET_strdup("missing parameter code");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
+    handle->edesc = GNUNET_strdup ("missing parameter code");
     handle->response_code = MHD_HTTP_BAD_REQUEST;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
     return;
@@ -1538,194 +1722,110 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
   code = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
                                             &cache_key);
 
-  //REQUIRED redirect_uri
-  GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
+  // REQUIRED redirect_uri
+  GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY,
+                      strlen (OIDC_REDIRECT_URI_KEY),
                       &cache_key);
-  if ( GNUNET_NO
-       == GNUNET_CONTAINER_multihashmap_contains (
-                                                  handle->rest_handle->url_param_map, &cache_key) )
+  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
+                                                             ->url_param_map,
+                                                           &cache_key))
   {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg = GNUNET_strdup("invalid_request");
-    handle->edesc = GNUNET_strdup("missing parameter redirect_uri");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
+    handle->edesc = GNUNET_strdup ("missing parameter redirect_uri");
     handle->response_code = MHD_HTTP_BAD_REQUEST;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
     return;
   }
 
-  //Check parameter grant_type == "authorization_code"
-  if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type))
+  // Check parameter grant_type == "authorization_code"
+  if (0 != strcmp (OIDC_GRANT_TYPE_VALUE, grant_type))
   {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg=GNUNET_strdup("unsupported_grant_type");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE);
     handle->response_code = MHD_HTTP_BAD_REQUEST;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
     return;
   }
   GNUNET_CRYPTO_hash (code, strlen (code), &cache_key);
-  int i = 1;
-  if ( GNUNET_SYSERR
-       == GNUNET_CONTAINER_multihashmap_put (OIDC_ticket_once,
-                                             &cache_key,
-                                             &i,
-                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) )
-  {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg = GNUNET_strdup("invalid_request");
-    handle->edesc = GNUNET_strdup("Cannot use the same code more than once");
-    handle->response_code = MHD_HTTP_BAD_REQUEST;
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
-    return;
-  }
-
-  //decode code
-  GNUNET_STRINGS_base64_decode(code,strlen(code), (void**)&code_output);
-  root = json_loads (code_output, 0, &error);
-  GNUNET_free(code_output);
-  ticket_string = json_object_get (root, "ticket");
-  nonce = json_object_get (root, "nonce");
-
-  if(ticket_string == NULL && !json_is_string(ticket_string))
-  {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg = GNUNET_strdup("invalid_request");
-    handle->edesc = GNUNET_strdup("invalid code");
+  if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (
+                         OIDC_used_ticket_map,
+                         &cache_key,
+                         &i,
+                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+  {
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
+    handle->edesc = GNUNET_strdup ("Cannot use the same code more than once");
     handle->response_code = MHD_HTTP_BAD_REQUEST;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
     return;
   }
 
-  struct GNUNET_RECLAIM_Ticket *ticket = GNUNET_new(struct GNUNET_RECLAIM_Ticket);
-  if ( GNUNET_OK
-       != GNUNET_STRINGS_string_to_data (json_string_value(ticket_string),
-                                         strlen (json_string_value(ticket_string)),
-                                         ticket,
-                                         sizeof(struct GNUNET_RECLAIM_Ticket)))
-  {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg = GNUNET_strdup("invalid_request");
-    handle->edesc = GNUNET_strdup("invalid code");
-    handle->response_code = MHD_HTTP_BAD_REQUEST;
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
-    GNUNET_free(ticket);
-    return;
-  }
-  // this is the current client (relying party)
-  struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
-  GNUNET_IDENTITY_ego_get_public_key(handle->ego_entry->ego,&pub_key);
-  if (0 != memcmp(&pub_key,&ticket->audience,sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
+  // decode code
+  if (GNUNET_OK != OIDC_parse_authz_code (&cid, code, &ticket, &cl, &nonce))
   {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg = GNUNET_strdup("invalid_request");
-    handle->edesc = GNUNET_strdup("invalid code");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
+    handle->edesc = GNUNET_strdup ("invalid code");
     handle->response_code = MHD_HTTP_BAD_REQUEST;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
-    GNUNET_free(ticket);
     return;
   }
 
-  //create jwt
-  struct GNUNET_TIME_Relative expiration_time;
-  if ( GNUNET_OK
-       != GNUNET_CONFIGURATION_get_value_time(cfg, "reclaim-rest-plugin",
-                                              "expiration_time", &expiration_time) )
+  // create jwt
+  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
+                                                        "reclaim-rest-plugin",
+                                                        "expiration_time",
+                                                        &expiration_time))
   {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg = GNUNET_strdup("server_error");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR);
     handle->edesc = GNUNET_strdup ("gnunet configuration failed");
     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
-    GNUNET_free(ticket);
     return;
   }
 
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *cl = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
-
-  //TODO OPTIONAL acr,amr,azp
 
-  struct EgoEntry *ego_entry;
-  for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next)
-  {
-    GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
-    if (0 == memcmp (&pub_key, &ticket->audience, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
-    {
-      break;
-    }
-  }
-  if ( NULL == ego_entry )
+  // TODO OPTIONAL acr,amr,azp
+  if (GNUNET_NO == ego_exists (handle, &ticket.audience))
   {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg = GNUNET_strdup("invalid_request");
-    handle->edesc = GNUNET_strdup("invalid code...");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
+    handle->edesc = GNUNET_strdup ("invalid code...");
     handle->response_code = MHD_HTTP_BAD_REQUEST;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
-    GNUNET_free(ticket);
-    return;
   }
-  if ( GNUNET_OK
-       != GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin",
-                                                 "jwt_secret", &jwt_secret) )
+  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
+                                                          "reclaim-rest-plugin",
+                                                          "jwt_secret",
+                                                          &jwt_secret))
   {
-    GNUNET_free_non_null(user_psw);
-    handle->emsg = GNUNET_strdup("invalid_request");
-    handle->edesc = GNUNET_strdup("No signing secret configured!");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
+    handle->edesc = GNUNET_strdup ("No signing secret configured!");
     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
-    GNUNET_free(ticket);
     return;
   }
-  char *id_token = jwt_create_from_list(&ticket->audience,
-                                        &ticket->identity,
-                                        cl,
-                                        &expiration_time,
-                                        (NULL != nonce && json_is_string(nonce)) ? json_string_value (nonce) : NULL,
-                                        jwt_secret);
-
-  //Create random access_token
-  char* access_token_number;
-  char* access_token;
-  uint64_t random_number;
-  random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
-  GNUNET_asprintf(&access_token_number, "%" PRIu64, random_number);
-  GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token);
-
-
-
-  //TODO OPTIONAL add refresh_token and scope
-  GNUNET_asprintf (&json_response,
-                   "{ \"access_token\" : \"%s\", "
-                   "\"token_type\" : \"Bearer\", "
-                   "\"expires_in\" : %d, "
-                   "\"id_token\" : \"%s\"}",
-                   access_token,
-                   expiration_time,
-                   id_token);
-  GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key);
-  char *id_ticket_combination;
-  GNUNET_asprintf(&id_ticket_combination,
-                  "%s;%s",
-                  client_id,
-                  json_string_value(ticket_string));
-  GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token,
-                                    &cache_key,
-                                    id_ticket_combination,
-                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
-
+  // TODO We should collect the attributes here. cl always empty
+  id_token = OIDC_id_token_new (&ticket.audience,
+                                &ticket.identity,
+                                cl,
+                                &expiration_time,
+                                (NULL != nonce) ? nonce : NULL,
+                                jwt_secret);
+  access_token = OIDC_access_token_new ();
+  OIDC_build_token_response (access_token,
+                             id_token,
+                             &expiration_time,
+                             &json_response);
+
+  persist_access_token (handle, access_token, &ticket);
   resp = GNUNET_REST_create_response (json_response);
   MHD_add_response_header (resp, "Cache-Control", "no-store");
   MHD_add_response_header (resp, "Pragma", "no-cache");
   MHD_add_response_header (resp, "Content-Type", "application/json");
   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
-
-  GNUNET_RECLAIM_ATTRIBUTE_list_destroy(cl);
-  GNUNET_free(access_token_number);
-  GNUNET_free(access_token);
-  GNUNET_free(user_psw);
-  GNUNET_free(json_response);
-  GNUNET_free(ticket);
-  GNUNET_free(id_token);
-  json_decref (root);
-  GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle);
+  GNUNET_RECLAIM_ATTRIBUTE_list_destroy (cl);
+  GNUNET_free (access_token);
+  GNUNET_free (json_response);
+  GNUNET_free (id_token);
+  GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
 }
 
 /**
@@ -1745,17 +1845,11 @@ consume_ticket (void *cls,
     GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle);
     return;
   }
-
   tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
                                                         attr->data,
                                                         attr->data_size);
-
   value = json_string (tmp_value);
-
-
-  json_object_set_new (handle->oidc->response,
-                       attr->name,
-                       value);
+  json_object_set_new (handle->oidc->response, attr->name, value);
   GNUNET_free (tmp_value);
 }
 
@@ -1768,143 +1862,109 @@ consume_ticket (void *cls,
  */
 static void
 userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
-                   const char* url, void *cls)
+                   const char *url,
+                   void *cls)
 {
-  //TODO expiration time
+  // TODO expiration time
   struct RequestHandle *handle = cls;
   char delimiter[] = " ";
-  char delimiter_db[] = ";";
   struct GNUNET_HashCode cache_key;
-  char *authorization, *authorization_type, *authorization_access_token;
-  char *client_ticket, *client, *ticket_str;
+  char *authorization;
+  char *authorization_type;
+  char *authorization_access_token;
   struct GNUNET_RECLAIM_Ticket *ticket;
+  const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
+  struct GNUNET_CRYPTO_EcdsaPublicKey pk;
+
 
   GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
                       strlen (OIDC_AUTHORIZATION_HEADER_KEY),
                       &cache_key);
-  if ( GNUNET_NO
-       == GNUNET_CONTAINER_multihashmap_contains (
-                                                  handle->rest_handle->header_param_map, &cache_key) )
+  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle
+                                                             ->header_param_map,
+                                                           &cache_key))
   {
-    handle->emsg = GNUNET_strdup("invalid_token");
-    handle->edesc = GNUNET_strdup("No Access Token");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
+    handle->edesc = GNUNET_strdup ("No Access Token");
     handle->response_code = MHD_HTTP_UNAUTHORIZED;
     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
     return;
   }
-  authorization = GNUNET_CONTAINER_multihashmap_get (
-                                                     handle->rest_handle->header_param_map, &cache_key);
+  authorization =
+    GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map,
+                                       &cache_key);
 
-  //split header in "Bearer" and access_token
-  authorization = GNUNET_strdup(authorization);
+  // split header in "Bearer" and access_token
+  authorization = GNUNET_strdup (authorization);
   authorization_type = strtok (authorization, delimiter);
-  if ( 0 != strcmp ("Bearer", authorization_type) )
+  if (0 != strcmp ("Bearer", authorization_type))
   {
-    handle->emsg = GNUNET_strdup("invalid_token");
-    handle->edesc = GNUNET_strdup("No Access Token");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
+    handle->edesc = GNUNET_strdup ("No Access Token");
     handle->response_code = MHD_HTTP_UNAUTHORIZED;
     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
-    GNUNET_free(authorization);
+    GNUNET_free (authorization);
     return;
   }
   authorization_access_token = strtok (NULL, delimiter);
-  if ( NULL == authorization_access_token )
+  if (NULL == authorization_access_token)
   {
-    handle->emsg = GNUNET_strdup("invalid_token");
-    handle->edesc = GNUNET_strdup("No Access Token");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
+    handle->edesc = GNUNET_strdup ("Access token missing");
     handle->response_code = MHD_HTTP_UNAUTHORIZED;
     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
-    GNUNET_free(authorization);
+    GNUNET_free (authorization);
     return;
   }
 
   GNUNET_CRYPTO_hash (authorization_access_token,
                       strlen (authorization_access_token),
                       &cache_key);
-  if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_interpret_access_token,
-                                                            &cache_key) )
+  if (GNUNET_NO ==
+      GNUNET_CONTAINER_multihashmap_contains (OIDC_access_token_map,
+                                              &cache_key))
   {
-    handle->emsg = GNUNET_strdup("invalid_token");
-    handle->edesc = GNUNET_strdup("The Access Token expired");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
+    handle->edesc = GNUNET_strdup ("The access token expired");
     handle->response_code = MHD_HTTP_UNAUTHORIZED;
     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
-    GNUNET_free(authorization);
+    GNUNET_free (authorization);
     return;
   }
+  ticket =
+    GNUNET_CONTAINER_multihashmap_get (OIDC_access_token_map, &cache_key);
+  GNUNET_assert (NULL != ticket);
 
-  client_ticket = GNUNET_CONTAINER_multihashmap_get(OIDC_interpret_access_token,
-                                                    &cache_key);
-  client_ticket = GNUNET_strdup(client_ticket);
-  client = strtok(client_ticket,delimiter_db);
-  if (NULL == client)
-  {
-    handle->emsg = GNUNET_strdup("invalid_token");
-    handle->edesc = GNUNET_strdup("The Access Token expired");
-    handle->response_code = MHD_HTTP_UNAUTHORIZED;
-    GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
-    GNUNET_free(authorization);
-    GNUNET_free(client_ticket);
-    return;
-  }
-  handle->ego_entry = handle->ego_head;
-  for(; NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
+  for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry;
+       handle->ego_entry = handle->ego_entry->next)
   {
-    if (0 == strcmp(handle->ego_entry->keystring,client))
-    {
-      break;
-    }
+    GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &pk);
+    if (0 == GNUNET_memcmp (&pk, &ticket->audience))
+      break; // Found
   }
   if (NULL == handle->ego_entry)
   {
-    handle->emsg = GNUNET_strdup("invalid_token");
-    handle->edesc = GNUNET_strdup("The Access Token expired");
-    handle->response_code = MHD_HTTP_UNAUTHORIZED;
-    GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
-    GNUNET_free(authorization);
-    GNUNET_free(client_ticket);
-    return;
-  }
-  ticket_str = strtok(NULL, delimiter_db);
-  if (NULL == ticket_str)
-  {
-    handle->emsg = GNUNET_strdup("invalid_token");
-    handle->edesc = GNUNET_strdup("The Access Token expired");
-    handle->response_code = MHD_HTTP_UNAUTHORIZED;
-    GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
-    GNUNET_free(authorization);
-    GNUNET_free(client_ticket);
-    return;
-  }
-  ticket = GNUNET_new(struct GNUNET_RECLAIM_Ticket);
-  if ( GNUNET_OK
-       != GNUNET_STRINGS_string_to_data (ticket_str,
-                                         strlen (ticket_str),
-                                         ticket,
-                                         sizeof(struct GNUNET_RECLAIM_Ticket)))
-  {
-    handle->emsg = GNUNET_strdup("invalid_token");
-    handle->edesc = GNUNET_strdup("The Access Token expired");
+    handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN);
+    handle->edesc = GNUNET_strdup ("The access token expired");
     handle->response_code = MHD_HTTP_UNAUTHORIZED;
     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
-    GNUNET_free(ticket);
-    GNUNET_free(authorization);
-    GNUNET_free(client_ticket);
+    GNUNET_free (authorization);
     return;
   }
 
   handle->idp = GNUNET_RECLAIM_connect (cfg);
-  handle->oidc->response = json_object();
-  json_object_set_new( handle->oidc->response, "sub", json_string( handle->ego_entry->keystring));
-  handle->idp_op = GNUNET_RECLAIM_ticket_consume (
-                                                  handle->idp,
-                                                  GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego),
+  handle->oidc->response = json_object ();
+  json_object_set_new (handle->oidc->response,
+                       "sub",
+                       json_string (handle->ego_entry->keystring));
+  privkey = GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
+
+  handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
+                                                  privkey,
                                                   ticket,
                                                   consume_ticket,
                                                   handle);
-  GNUNET_free(ticket);
-  GNUNET_free(authorization);
-  GNUNET_free(client_ticket);
-
+  GNUNET_free (authorization);
 }
 
 
@@ -1917,22 +1977,20 @@ static void
 init_cont (struct RequestHandle *handle)
 {
   struct GNUNET_REST_RequestHandlerError err;
-  static const struct GNUNET_REST_RequestHandler handlers[] = {
-    {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint},
-    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, //url-encoded
-    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
-    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
-    {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
-    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
-    {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC,
-      &options_cont},
-    GNUNET_REST_HANDLER_END
-  };
-
-  if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
-                                               handlers,
-                                               &err,
-                                               handle))
+  static const struct GNUNET_REST_RequestHandler handlers[] =
+    {{MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint},
+     {MHD_HTTP_METHOD_POST,
+      GNUNET_REST_API_NS_AUTHORIZE,
+      &authorize_endpoint}, // url-encoded
+     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
+     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint},
+     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint},
+     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint},
+     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, &options_cont},
+     GNUNET_REST_HANDLER_END};
+
+  if (GNUNET_NO ==
+      GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
   {
     handle->response_code = err.error_code;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
@@ -1988,63 +2046,77 @@ list_ego (void *cls,
     init_cont (handle);
     return;
   }
-  if (ID_REST_STATE_INIT == handle->state) {
+  if (ID_REST_STATE_INIT == handle->state)
+  {
     ego_entry = GNUNET_new (struct EgoEntry);
     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
-    ego_entry->keystring =
-      GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
+    ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
     ego_entry->ego = ego;
     ego_entry->identifier = GNUNET_strdup (identifier);
-    GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
+    GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
+                                      handle->ego_tail,
+                                      ego_entry);
     return;
   }
   /* Ego renamed or added */
-  if (identifier != NULL) {
-    for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) {
-      if (ego_entry->ego == ego) {
+  if (identifier != NULL)
+  {
+    for (ego_entry = handle->ego_head; NULL != ego_entry;
+         ego_entry = ego_entry->next)
+    {
+      if (ego_entry->ego == ego)
+      {
         /* Rename */
         GNUNET_free (ego_entry->identifier);
         ego_entry->identifier = GNUNET_strdup (identifier);
         break;
       }
     }
-    if (NULL == ego_entry) {
+    if (NULL == ego_entry)
+    {
       /* Add */
       ego_entry = GNUNET_new (struct EgoEntry);
       GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
-      ego_entry->keystring =
-        GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
+      ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
       ego_entry->ego = ego;
       ego_entry->identifier = GNUNET_strdup (identifier);
-      GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
+      GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
+                                        handle->ego_tail,
+                                        ego_entry);
     }
-  } else {
+  }
+  else
+  {
     /* Delete */
-    for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) {
+    for (ego_entry = handle->ego_head; NULL != ego_entry;
+         ego_entry = ego_entry->next)
+    {
       if (ego_entry->ego == ego)
         break;
     }
     if (NULL != ego_entry)
-      GNUNET_CONTAINER_DLL_remove(handle->ego_head,handle->ego_tail, ego_entry);
+      GNUNET_CONTAINER_DLL_remove (handle->ego_head,
+                                   handle->ego_tail,
+                                   ego_entry);
   }
-
 }
 
 static void
-rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
-                              GNUNET_REST_ResultProcessor proc,
-                              void *proc_cls)
+rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
+                               GNUNET_REST_ResultProcessor proc,
+                               void *proc_cls)
 {
   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
   handle->oidc = GNUNET_new (struct OIDC_Variables);
-  if ( NULL == OIDC_identity_login_time )
-    OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
-  if ( NULL == OIDC_identity_grants )
+  if (NULL == OIDC_cookie_jar_map)
+    OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
+  if (NULL == OIDC_identity_grants)
     OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
-  if ( NULL == OIDC_ticket_once )
-    OIDC_ticket_once = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
-  if ( NULL == OIDC_interpret_access_token )
-    OIDC_interpret_access_token = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
+  if (NULL == OIDC_used_ticket_map)
+    OIDC_used_ticket_map = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
+  if (NULL == OIDC_access_token_map)
+    OIDC_access_token_map =
+      GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
   handle->response_code = 0;
   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
   handle->proc_cls = proc_cls;
@@ -2053,20 +2125,15 @@ rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
   handle->rest_handle = rest_handle;
 
   handle->url = GNUNET_strdup (rest_handle->url);
-  if (handle->url[strlen (handle->url)-1] == '/')
-    handle->url[strlen (handle->url)-1] = '\0';
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Connecting...\n");
-  handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
-                                                     &list_ego,
-                                                     handle);
+  if (handle->url[strlen (handle->url) - 1] == '/')
+    handle->url[strlen (handle->url) - 1] = '\0';
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
+  handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
+  handle->gns_handle = GNUNET_GNS_connect (cfg);
   handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
   handle->timeout_task =
-    GNUNET_SCHEDULER_add_delayed (handle->timeout,
-                                  &do_timeout,
-                                  handle);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Connected\n");
+    GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
 }
 
 /**
@@ -2083,7 +2150,7 @@ libgnunet_plugin_rest_openid_connect_init (void *cls)
 
   cfg = cls;
   if (NULL != plugin.cfg)
-    return NULL;                /* can only initialize once! */
+    return NULL; /* can only initialize once! */
   memset (&plugin, 0, sizeof (struct Plugin));
   plugin.cfg = cfg;
   api = GNUNET_new (struct GNUNET_REST_Plugin);
@@ -2099,7 +2166,7 @@ libgnunet_plugin_rest_openid_connect_init (void *cls)
                    MHD_HTTP_METHOD_OPTIONS);
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              _("Identity Provider REST API initialized\n"));
+              _ ("Identity Provider REST API initialized\n"));
   return api;
 }
 
@@ -2119,40 +2186,34 @@ libgnunet_plugin_rest_openid_connect_done (void *cls)
 
   struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
   void *value = NULL;
-  hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (
-                                                              OIDC_identity_login_time);
+  hashmap_it =
+    GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_cookie_jar_map);
   while (GNUNET_YES ==
          GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
-  {
-    if (NULL != value)
-      GNUNET_free(value);
-  }
-  GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time);
-  hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants);
+    GNUNET_free_non_null (value);
+  GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map);
+
+  hashmap_it =
+    GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants);
   while (GNUNET_YES ==
          GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
-  {
-    if (NULL != value)
-      GNUNET_free(value);
-  }
-  GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants);
-  hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_ticket_once);
+    GNUNET_free_non_null (value);
+  GNUNET_CONTAINER_multihashmap_destroy (OIDC_identity_grants);
+
+  hashmap_it =
+    GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_used_ticket_map);
   while (GNUNET_YES ==
          GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
-  {
-    if (NULL != value)
-      GNUNET_free(value);
-  }
-  GNUNET_CONTAINER_multihashmap_destroy(OIDC_ticket_once);
-  hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_interpret_access_token);
+    GNUNET_free_non_null (value);
+  GNUNET_CONTAINER_multihashmap_destroy (OIDC_used_ticket_map);
+
+  hashmap_it =
+    GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_access_token_map);
   while (GNUNET_YES ==
          GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
-  {
-    if (NULL != value)
-      GNUNET_free(value);
-  }
-  GNUNET_CONTAINER_multihashmap_destroy(OIDC_interpret_access_token);
-  GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it);
+    GNUNET_free_non_null (value);
+  GNUNET_CONTAINER_multihashmap_destroy (OIDC_access_token_map);
+  GNUNET_CONTAINER_multihashmap_iterator_destroy (hashmap_it);
   GNUNET_free_non_null (allow_methods);
   GNUNET_free (api);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,