-wip token request
[oweals/gnunet.git] / src / identity-provider / plugin_rest_identity_provider.c
index ac9d2bd08dac11aaaca5248e65d8a5e56418a193..ca42cc50ca5b60ecdb492cfd3a6aec32daf6b819 100644 (file)
 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume"
 
 /**
- * Authorize namespace
+ * Authorize endpoint
  */
 #define GNUNET_REST_API_NS_AUTHORIZE "/idp/authorize"
 
+/**
+ * Token endpoint
+ */
+#define GNUNET_REST_API_NS_TOKEN "/idp/token"
+
 /**
  * Login namespace
  */
  */
 #define OIDC_COOKIE_HEADER_KEY "Cookie"
 
+/**
+ * OIDC cookie header information key
+ */
+#define OIDC_AUTHORIZATION_HEADER_KEY "Authorization"
+
+
 /**
  * OIDC cookie header information key
  */
  * OIDC expected scope part while authorizing
  */
 #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
+
 /**
  * OIDC ignored parameter array
  */
@@ -168,7 +180,12 @@ char* OIDC_ignored_parameter_array [] =
 /**
  * OIDC authorized identities and times hashmap
  */
-struct GNUNET_CONTAINER_MultiHashMap *OIDC_authorized_identities;
+struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time;
+
+/**
+ * OIDC authorized identities and times hashmap
+ */
+struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants;
 
 /**
  * The configuration handle
@@ -188,6 +205,30 @@ struct Plugin
   const struct GNUNET_CONFIGURATION_Handle *cfg;
 };
 
+struct OIDC_Variables
+{
+
+  struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey;
+
+  char *client_id;
+
+  int is_client_trusted;
+
+  char *redirect_uri;
+
+  char *scope;
+
+  char *state;
+
+  char *nonce;
+
+  char *response_type;
+
+  char *login_identity;
+
+  json_t *post_object;
+};
+
 /**
  * The ego list
  */
@@ -238,9 +279,14 @@ struct RequestHandle
   struct EgoEntry *ego_entry;
 
   /**
-   * Ptr to current ego private key
+   * Pointer to ego private key
    */
-  const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
+  struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
+
+  /**
+   * OIDC variables
+   */
+  struct OIDC_Variables *oidc;
 
   /**
    * The processing state
@@ -258,10 +304,20 @@ struct RequestHandle
   struct GNUNET_REST_RequestHandle *rest_handle;
 
   /**
-   * Zone connection
+   * Handle to NAMESTORE
    */
   struct GNUNET_NAMESTORE_Handle *namestore_handle;
 
+  /**
+   * Iterator for NAMESTORE
+   */
+  struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
+
+  /**
+   * Attribute claim list
+   */
+  struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attr_list;
+
   /**
    * IDENTITY Operation
    */
@@ -317,11 +373,6 @@ struct RequestHandle
    */
   char *emsg;
 
-  /**
-   * Error response uri
-   */
-  char *eredirect;
-
   /**
    * Error response description
    */
@@ -339,8 +390,6 @@ struct RequestHandle
 
 };
 
-
-
 /**
  * Cleanup lookup handle
  * @param handle Handle to clean up
@@ -348,6 +397,8 @@ struct RequestHandle
 static void
 cleanup_handle (struct RequestHandle *handle)
 {
+  struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_entry;
+  struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_tmp;
   struct EgoEntry *ego_entry;
   struct EgoEntry *ego_tmp;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -370,8 +421,40 @@ cleanup_handle (struct RequestHandle *handle)
     GNUNET_free (handle->emsg);
   if (NULL != handle->edesc)
     GNUNET_free (handle->edesc);
-  if (NULL != handle->eredirect)
-    GNUNET_free (handle->eredirect);
+  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->post_object)
+      json_decref(handle->oidc->post_object);
+    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 (handle->attr_list);
+  }
   for (ego_entry = handle->ego_head;
        NULL != ego_entry;)
   {
@@ -381,6 +464,10 @@ 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 (handle);
 }
 
@@ -403,12 +490,19 @@ do_error (void *cls)
   struct MHD_Response *resp;
   char *json_error;
 
-  GNUNET_asprintf (&json_error,
-                   "{error : %s}",
-                   handle->emsg);
+  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 )
+  {
+    handle->response_code = MHD_HTTP_BAD_REQUEST;
+  }
   resp = GNUNET_REST_create_response (json_error);
   handle->proc (handle->proc_cls, resp, handle->response_code);
-  cleanup_handle (handle);
+  GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
   GNUNET_free (json_error);
 }
 
@@ -423,14 +517,15 @@ do_redirect_error (void *cls)
   struct RequestHandle *handle = cls;
   struct MHD_Response *resp;
   char* redirect;
-  //TODO handle->url is wrong
   GNUNET_asprintf (&redirect,
-                   "%s?error=%s&error_description=%s",
-                  handle->eredirect, handle->emsg, handle->edesc );
+                   "%s?error=%s&error_description=%s%s%s",
+                  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 ("");
   MHD_add_response_header (resp, "Location", redirect);
   handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
-  cleanup_handle (handle);
+  GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
   GNUNET_free (redirect);
 }
 
@@ -743,6 +838,7 @@ attr_collect (void *cls,
   struct GNUNET_JSONAPI_Resource *json_resource;
   struct RequestHandle *handle = cls;
   json_t *value;
+  char* tmp_value;
   
   if ((NULL == attr->name) || (NULL == attr->data))
   {
@@ -756,11 +852,17 @@ attr_collect (void *cls,
                                                attr->name);
   GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
 
-  value = json_string (attr->data);
+  tmp_value = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type,
+                                           attr->data,
+                                           attr->data_size);
+
+  value = json_string (tmp_value);
+
   GNUNET_JSONAPI_resource_add_attr (json_resource,
                                     "value",
                                     value);
   json_decref (value);
+  GNUNET_free(tmp_value);
   GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
 }
 
@@ -911,10 +1013,10 @@ revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
                                  strlen (rnd_str),
                                  &ticket.rnd,
                                  sizeof (uint64_t));
-//  GNUNET_STRINGS_string_to_data (identity_str,
-//                                 strlen (identity_str),
-//                                 &ticket.identity,type filter text
-//                                 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+  GNUNET_STRINGS_string_to_data (identity_str,
+                                 strlen (identity_str),
+                                 &ticket.identity,
+                                 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
   GNUNET_STRINGS_string_to_data (audience_str,
                                  strlen (audience_str),
                                  &ticket.audience,
@@ -1131,490 +1233,683 @@ options_cont (struct GNUNET_REST_RequestHandle *con_handle,
 }
 
 /**
- * Function called if we had an error in zone-to-name mapping.
+ * Cookie interpretation
  */
 static void
-zone_to_name_error (void *cls)
+cookie_identity_interpretation (struct RequestHandle *handle)
 {
-  struct RequestHandle *handle = cls;
+  struct GNUNET_HashCode cache_key;
+  char* cookies;
+  struct GNUNET_TIME_Absolute current_time, *relog_time;
+  char delimiter[] = "; ";
 
-  handle->emsg = GNUNET_strdup("unauthorized_client");
-  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+  //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) )
+  {
+    //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_NAMESTORE_disconnect (handle->namestore_handle);
-  handle->namestore_handle = NULL;
-  GNUNET_SCHEDULER_add_now (&do_error, handle);
+    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;
+    }
+  }
 }
 
 /**
- * Test if a name mapping was found, if so, continue, else, throw error
- *
- * @param cls closure
- * @param zone_key public key of the zone
- * @param name name that is being mapped (at most 255 characters long)
- * @param rd_count number of entries in @a rd array
- * @param rd array of records with data to store
+ * Login redirection
  */
 static void
-zone_to_name_get_cb (void *cls,
-                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
-                const char *name,
-                unsigned int rd_count,
-                const struct GNUNET_GNSRECORD_Data *rd)
+login_redirection(void *cls)
 {
+  char *login_base_url;
+  char *new_redirect;
+  struct MHD_Response *resp;
   struct RequestHandle *handle = cls;
 
-
-  if (0 == rd_count)
+  if ( GNUNET_OK
+      == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
+                                               "address", &login_base_url) )
   {
-    handle->emsg = GNUNET_strdup("unauthorized_client");
+    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,
+                    OIDC_CLIENT_ID_KEY,
+                    handle->oidc->client_id,
+                    OIDC_REDIRECT_URI_KEY,
+                    handle->oidc->redirect_uri,
+                    OIDC_SCOPE_KEY,
+                    handle->oidc->scope,
+                    OIDC_STATE_KEY,
+                    (NULL != handle->oidc->state) ? handle->oidc->state : "",
+                    OIDC_NONCE_KEY,
+                    (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);
+  }
+  else
+  {
+    handle->emsg = GNUNET_strdup("server_error");
+    handle->edesc = GNUNET_strdup ("gnunet configuration failed");
     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
-
-    GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
-    handle->namestore_handle = NULL;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
     return;
   }
+  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
+  GNUNET_free(new_redirect);
+  GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
 }
 
 /**
- * Respond to authorization GET request
- *
- * @param con_handle the connection handle
- * @param url the url
- * @param cls the RequestHandle
+ * Function called if we had an error in zone-to-name mapping.
  */
 static void
-authorize_get_cont (struct GNUNET_REST_RequestHandle *con_handle,
-                const char* url,
-                void *cls)
+oidc_iteration_error (void *cls)
 {
-    /**        The Authorization Server MUST validate all the OAuth 2.0 parameters
-   *   according to the OAuth 2.0 specification.
-   */
-  /**
-   *   If the sub (subject) Claim is requested with a specific value for the
-   *   ID Token, the Authorization Server MUST only send a positive response
-   *   if the End-User identified by that sub value has an active session with
-   *   the Authorization Server or has been Authenticated as a result of the
-   *   request. The Authorization Server MUST NOT reply with an ID Token or
-   *   Access Token for a different user, even if they have an active session
-   *   with the Authorization Server. Such a request can be made either using
-   *   an id_token_hint parameter or by requesting a specific Claim Value as
-   *   described in Section 5.5.1, if the claims parameter is supported by
-   *   the implementation.
-   */
+  struct RequestHandle *handle = cls;
+  handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR");
+  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+  GNUNET_SCHEDULER_add_now (&do_error, handle);
+}
 
-  struct MHD_Response *resp;
+static void
+oidc_ticket_issue_cb (void* cls,
+                 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
+{
   struct RequestHandle *handle = cls;
-  char *response_type;
-  char *client_id;
-  char *scope;
-  char *redirect_uri;
-  char *expected_redirect_uri;
-  char *state = NULL;
-  char *nonce = NULL;
-  struct GNUNET_TIME_Absolute current_time, *relog_time;
-  char *login_base_url, *new_redirect;
+  struct MHD_Response *resp;
   struct GNUNET_HashCode cache_key;
-  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_pkey;
-  struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
-  int number_of_ignored_parameter, iterator;
-
-  // 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->emsg=GNUNET_strdup("invalid_request");
-    handle->edesc=GNUNET_strdup("Missing parameter: client_id");
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
+  char* ticket_str;
+  char* redirect_uri;
+  char* jwt;
+  handle->idp_op = NULL;
+  resp = GNUNET_REST_create_response ("");
+  if (NULL != ticket) {
+    ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket,
+                                                      sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket));
+
+
+    //TODO Check if this is right:
+//    GNUNET_CRYPTO_hash (ticket_str, strlen (ticket_str), &cache_key);
+//    jwt = jwt_create_from_list (handle->oidc->client_pkey,
+//                             handle->attr_list,
+//                             handle->priv_key);
+//    //TODO Check success of function
+//    GNUNET_CONTAINER_multihashmap_put (
+//     OIDC_identity_grants, &cache_key, jwt,
+//     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+
+
+    GNUNET_asprintf (&redirect_uri, "%s?%s=%s&state=%s",
+                    handle->oidc->redirect_uri,
+                    handle->oidc->response_type,
+                    ticket_str, handle->oidc->state);
+    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);
+    GNUNET_free (ticket_str);
     return;
   }
-  client_id = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
-                                               &cache_key);
-  if ( GNUNET_OK
-      != GNUNET_CRYPTO_ecdsa_public_key_from_string (client_id,
-                                                    strlen (client_id),
-                                                    &pubkey) )
-  {
-    handle->emsg=GNUNET_strdup("unauthorized_client");
-    handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
-  }
-
-  // Checks if client_id is valid:
-  handle->namestore_handle = GNUNET_NAMESTORE_connect(cfg);
-  zone_pkey = GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
-  GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle, zone_pkey, &pubkey,
-                                zone_to_name_error, handle, zone_to_name_get_cb,
-                                handle);
-  return;
+  handle->emsg = GNUNET_strdup("server_error");
+  handle->edesc = GNUNET_strdup("Server cannot generate ticket.");
+  GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+}
 
-  // 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))
+static void
+oidc_collect_finished_cb (void *cls)
+{
+  struct RequestHandle *handle = cls;
+  handle->attr_it = NULL;
+  handle->ticket_it = NULL;
+  if (NULL == handle->attr_list->list_head)
   {
-    handle->emsg=GNUNET_strdup("invalid_request");
-    handle->edesc=GNUNET_strdup("Missing parameter: redirect_uri");
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    handle->emsg = GNUNET_strdup("invalid_scope");
+    handle->edesc = GNUNET_strdup("The requested scope is not available.");
+    GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
     return;
   }
-  redirect_uri = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
-                                               &cache_key);
+  handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_issue (handle->idp,
+                                                    &handle->priv_key,
+                                                    &handle->oidc->client_pkey,
+                                                    handle->attr_list,
+                                                    &oidc_ticket_issue_cb,
+                                                    handle);
+}
 
-  GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", client_id);
 
-  // verify the redirect uri matches https://<client_id>.zkey[/xyz]
-  if( 0 != strncmp( expected_redirect_uri, redirect_uri, strlen(expected_redirect_uri)) )
+/**
+ * Collect all attributes for an ego
+ */
+static void
+oidc_attr_collect (void *cls,
+              const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
+              const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le;
+  char* scope_variables;
+  char* scope_variable;
+  char delimiter[]=" ";
+
+  if ( (NULL == attr->name) || (NULL == attr->data) )
   {
-    handle->emsg=GNUNET_strdup("invalid_request");
-    handle->edesc=GNUNET_strdup("Invalid redirect_uri");
-    GNUNET_free(expected_redirect_uri);
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
     return;
   }
-  handle->eredirect = GNUNET_strdup(redirect_uri);
 
-  // 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))
+  scope_variables = GNUNET_strdup(handle->oidc->scope);
+  scope_variable = strtok (scope_variables, delimiter);
+  while (NULL != scope_variable)
   {
-    handle->emsg=GNUNET_strdup("invalid_request");
-    handle->edesc=GNUNET_strdup("Missing parameter: response_type");
-    GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
-    return;
+    if ( 0 == strcmp (attr->name, scope_variable) )
+    {
+      break;
+    }
+    scope_variable = strtok (NULL, delimiter);
   }
-  response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
-                                                    &cache_key);
-
-  // 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))
+  if ( NULL == scope_variable )
   {
-    handle->emsg=GNUNET_strdup("invalid_request");
-    handle->edesc=GNUNET_strdup("Missing parameter: scope");
-    GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+    GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
     return;
   }
-  scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
-                                           &cache_key);
+  GNUNET_free(scope_variables);
 
-  //RECOMMENDED value: state
-  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))
-  {
-    state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
-                                             &cache_key);
-  }
+  le = GNUNET_new(struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry);
+  le->claim = GNUNET_IDENTITY_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_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
+}
 
-  //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))
-  {
-    nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
-                                             &cache_key);
-  }
 
-  number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
-  for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
+/**
+ * Cookie and Time check
+ */
+static void
+login_check (void *cls)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_TIME_Absolute current_time, *relog_time;
+  struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey;
+  struct GNUNET_HashCode cache_key;
+  char *identity_cookie;
+
+  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) )
   {
-    GNUNET_CRYPTO_hash (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))
+    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->emsg=GNUNET_strdup("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( 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.");
-    GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
-    return;
-  }
-  // Checks if scope contains 'openid'
-  if( NULL == strstr( scope, OIDC_EXPECTED_AUTHORIZATION_SCOPE ) )
-  {
-    handle->emsg=GNUNET_strdup("invalid_scope");
-    handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
-                               "malformed.");
-    GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
-    return;
+      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");
+       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)
+      {
+       GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
+       if ( 0
+           == memcmp (&ego_pkey, &pubkey,
+                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
+       {
+         handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (
+             handle->ego_entry->ego);
+         handle->resp_object = GNUNET_JSONAPI_document_new ();
+         handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
+         handle->attr_list = GNUNET_new(
+             struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList);
+         handle->attr_it = GNUNET_IDENTITY_PROVIDER_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);
+      return;
+    }
+    //GNUNET_free(relog_time);
   }
+}
 
-  //TODO check other values and use them accordingly
+/**
+ * Create a response with requested records
+ *
+ * @param handle the RequestHandle
+ */
+static void
+namestore_iteration_callback (
+    void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+    const char *rname, unsigned int rd_len,
+    const struct GNUNET_GNSRECORD_Data *rd)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_CRYPTO_EcdsaPublicKey login_identity_pkey;
+  struct GNUNET_CRYPTO_EcdsaPublicKey current_zone_pkey;
+  int i;
 
-  GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
-                     &cache_key);
-  //No identity-cookie -> redirect to login
-  if ( GNUNET_YES
-      == GNUNET_CONTAINER_multihashmap_contains (con_handle->header_param_map,
-                                                &cache_key) )
+  for (i = 0; i < rd_len; i++)
   {
-    //split cookies and find 'Identity' cookie
-    char* cookies = GNUNET_CONTAINER_multihashmap_get (
-       con_handle->header_param_map, &cache_key);
-    char delimiter[] = "; ";
-    char *identity_cookie;
-    identity_cookie = strtok(cookies, delimiter);
+    if ( GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type )
+      continue;
 
-    while ( NULL != identity_cookie )
+    if ( NULL != handle->oidc->login_identity )
     {
-      if ( NULL != strstr (identity_cookie, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
+      GNUNET_CRYPTO_ecdsa_public_key_from_string (
+         handle->oidc->login_identity,
+         strlen (handle->oidc->login_identity),
+         &login_identity_pkey);
+      GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego,
+                                         &current_zone_pkey);
+
+      if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
+                    sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
       {
-       break;
+       if ( 0 == memcmp (&login_identity_pkey, &current_zone_pkey,
+                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
+       {
+         handle->oidc->is_client_trusted = GNUNET_YES;
+       }
       }
-      identity_cookie = strtok (NULL, delimiter);
     }
-    GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
-
-    //No login time for identity -> redirect to login
-    if ( GNUNET_YES
-       == GNUNET_CONTAINER_multihashmap_contains (OIDC_authorized_identities,
-                                                  &cache_key) )
+    else
     {
-      relog_time = GNUNET_CONTAINER_multihashmap_get (
-             OIDC_authorized_identities, &cache_key);
+      if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
+                    sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
+      {
+       handle->oidc->is_client_trusted = GNUNET_YES;
+      }
+    }
+  }
 
-      current_time = GNUNET_TIME_absolute_get();
+  GNUNET_NAMESTORE_zone_iterator_next (handle->namestore_handle_it);
+}
 
-      GNUNET_CONTAINER_multihashmap_remove_all(OIDC_authorized_identities, &cache_key);
-      // 30 min after old login -> redirect to login
-      if ( current_time.abs_value_us <= relog_time->abs_value_us )
-      {
-       resp = GNUNET_REST_create_response ("");
+/**
+ * Iteration over all results finished, build final
+ * response.
+ *
+ * @param cls the `struct RequestHandle`
+ */
+static void namestore_iteration_finished_GET (void *cls)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_HashCode cache_key;
 
-       GNUNET_CRYPTO_ecdsa_public_key_from_string (identity_cookie,
-                                                   strlen (identity_cookie),
-                                                   &pubkey);
+  char *expected_redirect_uri;
+  char *expected_scope;
+  char delimiter[]=" ";
+  int number_of_ignored_parameter, iterator;
 
-       // iterate over egos and compare their public key
-//     GNUNET_IDENTITY_PROVIDER_get_attributes_start
-       // iterate over scope variables
-       char delimiter[] = " ";
-       char *scope_attribute;
-       scope_attribute = strtok(scope, delimiter);
 
-       while ( NULL != scope_attribute )
-       {
-         if ( NULL == strstr (scope_attribute, OIDC_EXPECTED_AUTHORIZATION_SCOPE) )
-         {
-           // claim attribute from ego
-           scope_attribute = strtok (NULL, delimiter);
-         }
-       }
-       // create an authorization code
+  handle->ego_entry = handle->ego_entry->next;
 
-//     GNUNET_IDENTITY_PROVIDER_t
+  if(NULL != handle->ego_entry)
+  {
+    handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
+    handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key,
+                                          &oidc_iteration_error, handle, &namestore_iteration_callback, handle,
+                                          &namestore_iteration_finished_GET, handle);
+    return;
+  }
+  if (GNUNET_NO == handle->oidc->is_client_trusted)
+  {
+    handle->emsg = GNUNET_strdup("unauthorized_client");
+    handle->edesc = GNUNET_strdup("The client is not authorized to request an "
+                                 "authorization code using this method.");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
 
-       MHD_add_response_header (resp, "Location", redirect_uri);
-       handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
-       cleanup_handle (handle);
-       GNUNET_free(relog_time);
-       return;
-      }
-      GNUNET_free(relog_time);
+  // 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->emsg=GNUNET_strdup("invalid_request");
+    handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  handle->oidc->redirect_uri = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
+                                               &cache_key);
+
+  GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", handle->oidc->client_id);
+  // verify the redirect uri matches https://<client_id>.zkey[/xyz]
+  if( 0 != strncmp( expected_redirect_uri, handle->oidc->redirect_uri, strlen(expected_redirect_uri)) )
+  {
+    handle->emsg=GNUNET_strdup("invalid_request");
+    handle->edesc=GNUNET_strdup("Invalid redirect_uri");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    GNUNET_free(expected_redirect_uri);
+    return;
+  }
+  handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
+
+  GNUNET_free(expected_redirect_uri);
+  // 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->emsg=GNUNET_strdup("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->emsg=GNUNET_strdup("invalid_request");
+    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);
+    //TODO: what do we do with the nonce?
+    handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
+  }
+
+  //TODO check other values and use them accordingly
+  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]),
+                       &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",
+                      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 ) )
+  {
+    handle->emsg=GNUNET_strdup("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;
+  }
 
-  // login redirection
-  if ( GNUNET_OK
-      == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
-                                               "address", &login_base_url) )
+  // Checks if scope contains 'openid'
+  expected_scope = GNUNET_strdup(handle->oidc->scope);
+  expected_scope = strtok (expected_scope, delimiter);
+  while (NULL != expected_scope)
   {
-    GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
-                    login_base_url,
-                    OIDC_RESPONSE_TYPE_KEY,
-                    response_type,
-                    OIDC_CLIENT_ID_KEY,
-                    client_id,
-                    OIDC_REDIRECT_URI_KEY,
-                    redirect_uri,
-                    OIDC_SCOPE_KEY,
-                    scope,
-                    OIDC_STATE_KEY,
-                    (NULL == state) ? state : "",
-                    OIDC_NONCE_KEY,
-                    (NULL == nonce) ? nonce : "");
-    resp = GNUNET_REST_create_response ("");
-    MHD_add_response_header (resp, "Location", new_redirect);
+    if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
+    {
+      break;
+    }
+    expected_scope = strtok (NULL, delimiter);
   }
-  else
+  if (NULL == expected_scope)
   {
-    handle->emsg = GNUNET_strdup("No server configuration");
-    handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    handle->emsg = GNUNET_strdup("invalid_scope");
+    handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
+                               "malformed.");
+    GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
     return;
   }
-  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
-  cleanup_handle (handle);
-  GNUNET_free(new_redirect);
-  return;
+
+  GNUNET_free(expected_scope);
+
+  if( NULL != handle->oidc->login_identity )
+  {
+    GNUNET_SCHEDULER_add_now(&login_check,handle);
+    return;
+  }
+
+  GNUNET_SCHEDULER_add_now(&login_redirection,handle);
 }
 
 /**
- * Respond to authorization POST request
+ * Responds to authorization GET request
  *
  * @param con_handle the connection handle
  * @param url the url
  * @param cls the RequestHandle
  */
 static void
-authorize_post_cont (struct GNUNET_REST_RequestHandle *con_handle,
+authorize_GET_cont (struct GNUNET_REST_RequestHandle *con_handle,
                 const char* url,
                 void *cls)
 {
-    /**        The Authorization Server MUST validate all the OAuth 2.0 parameters
-   *   according to the OAuth 2.0 specification.
-   */
-  /**
-   *   If the sub (subject) Claim is requested with a specific value for the
-   *   ID Token, the Authorization Server MUST only send a positive response
-   *   if the End-User identified by that sub value has an active session with
-   *   the Authorization Server or has been Authenticated as a result of the
-   *   request. The Authorization Server MUST NOT reply with an ID Token or
-   *   Access Token for a different user, even if they have an active session
-   *   with the Authorization Server. Such a request can be made either using
-   *   an id_token_hint parameter or by requesting a specific Claim Value as
-   *   described in Section 5.5.1, if the claims parameter is supported by
-   *   the implementation.
-   */
-
-  struct MHD_Response *resp;
   struct RequestHandle *handle = cls;
-  const char *response_type;
-  const char *client_id;
-  char *scope;
-  const char *redirect_uri;
-  const char *state = NULL;
-  const char *nonce = NULL;
-  struct GNUNET_TIME_Absolute current_time, *relog_time;
-  char *login_base_url;
-  char *new_redirect;
-  char *expected_redirect_uri;
-  json_t *cache_object;
-  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_pkey;
-  struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
   struct GNUNET_HashCode cache_key;
-  int number_of_ignored_parameter, iterator;
 
-  json_t *root;
-  json_error_t error;
-  root = json_loads (handle->rest_handle->data, 0, &error);
+  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);
+  }
 
   // REQUIRED value: client_id
-  cache_object = json_object_get (root, OIDC_CLIENT_ID_KEY);
-  if( NULL==cache_object || !json_is_string(cache_object))
+  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->emsg=GNUNET_strdup("invalid_request");
-    handle->edesc=GNUNET_strdup("Missing parameter: client_id");
+    handle->edesc=GNUNET_strdup("missing parameter client_id");
+    handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
     return;
   }
-  client_id = json_string_value(cache_object);
+  handle->oidc->client_id = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
+                                               &cache_key);
+  handle->oidc->client_id = GNUNET_strdup (handle->oidc->client_id);
+
   if ( GNUNET_OK
-      != GNUNET_CRYPTO_ecdsa_public_key_from_string (client_id,
-                                                    strlen (client_id),
-                                                    &pubkey) )
+      != 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->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+
+
+  if ( NULL == handle->ego_head )
   {
-    handle->emsg=GNUNET_strdup("unauthorized_client");
+    //TODO throw error or ignore if egos are missing?
+    handle->emsg = GNUNET_strdup("server_error");
+    handle->edesc = GNUNET_strdup ("Egos are missing");
     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
     GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
   }
 
+  handle->ego_entry = handle->ego_head;
+  handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
+  handle->oidc->is_client_trusted = GNUNET_NO;
+
   // Checks if client_id is valid:
-  handle->namestore_handle = GNUNET_NAMESTORE_connect(cfg);
-  zone_pkey = GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
-  //TODO: fix
-//  GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle, zone_pkey, &pubkey,
-//                              zone_to_name_error, handle, zone_to_name_cb,
-//                              handle);
+  handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
+      handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
+      handle, &namestore_iteration_callback, handle,
+      &namestore_iteration_finished_GET, handle);
+}
+
+/**
+ * Iteration over all results finished, build final
+ * response.
+ *
+ * @param cls the `struct RequestHandle`
+ */
+static void namestore_iteration_finished_POST (void *cls)
+{
+  struct RequestHandle *handle = cls;
+  json_t *cache_object;
+  char *expected_redirect_uri;
+  char *expected_scope;
+  char delimiter[]=" ";
+  int number_of_ignored_parameter, iterator;
+
+
+  handle->ego_entry = handle->ego_entry->next;
+
+  if(NULL != handle->ego_entry){
+    handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
+    handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key,
+                                          &oidc_iteration_error, handle, &namestore_iteration_callback, handle,
+                                          &namestore_iteration_finished_POST, handle);
+    return;
+  }
+  if (GNUNET_YES != handle->oidc->is_client_trusted)
+  {
+    handle->emsg = GNUNET_strdup("unauthorized_client");
+    handle->edesc = GNUNET_strdup("The client is not authorized to request an "
+                                 "authorization code using this method.");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
 
   // REQUIRED value: redirect_uri
-  cache_object = json_object_get (root, OIDC_REDIRECT_URI_KEY);
-  if( NULL==cache_object || !json_is_string(cache_object))
+  cache_object = json_object_get (handle->oidc->post_object, OIDC_REDIRECT_URI_KEY);
+  if ( NULL == cache_object || !json_is_string(cache_object) )
   {
     handle->emsg=GNUNET_strdup("invalid_request");
-    handle->edesc=GNUNET_strdup("Missing parameter: redirect_uri");
+    handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
     GNUNET_SCHEDULER_add_now (&do_error, handle);
     return;
   }
-  redirect_uri = json_string_value(cache_object);
-
-  GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", client_id);
+  handle->oidc->redirect_uri = json_string_value (cache_object);
 
+  GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", handle->oidc->client_id);
   // verify the redirect uri matches https://<client_id>.zkey[/xyz]
-  if( 0 != strncmp( expected_redirect_uri, redirect_uri, strlen(expected_redirect_uri)) )
+  if( 0 != strncmp( expected_redirect_uri, handle->oidc->redirect_uri, strlen(expected_redirect_uri)) )
   {
     handle->emsg=GNUNET_strdup("invalid_request");
     handle->edesc=GNUNET_strdup("Invalid redirect_uri");
-    GNUNET_free(expected_redirect_uri);
     GNUNET_SCHEDULER_add_now (&do_error, handle);
+    GNUNET_free(expected_redirect_uri);
     return;
   }
-  handle->eredirect = GNUNET_strdup(redirect_uri);
+  handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
+  GNUNET_free(expected_redirect_uri);
 
   // REQUIRED value: response_type
-  cache_object = json_object_get (root, OIDC_RESPONSE_TYPE_KEY);
-  if( NULL==cache_object || !json_is_string(cache_object))
+  cache_object = json_object_get (handle->oidc->post_object, OIDC_RESPONSE_TYPE_KEY);
+  if ( NULL == cache_object || !json_is_string(cache_object) )
   {
     handle->emsg=GNUNET_strdup("invalid_request");
-    handle->edesc=GNUNET_strdup("Missing parameter: response_type");
+    handle->edesc=GNUNET_strdup("missing parameter response_type");
     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
     return;
   }
-  response_type = json_string_value(cache_object);
+  handle->oidc->response_type = json_string_value (cache_object);
+  handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
 
   // REQUIRED value: scope
-  cache_object = json_object_get (root, OIDC_SCOPE_KEY);
-  if( NULL==cache_object || !json_is_string(cache_object))
+  cache_object = json_object_get (handle->oidc->post_object, OIDC_SCOPE_KEY);
+  if ( NULL == cache_object || !json_is_string(cache_object) )
   {
     handle->emsg=GNUNET_strdup("invalid_request");
-    handle->edesc=GNUNET_strdup("Missing parameter: scope");
+    handle->edesc=GNUNET_strdup("missing parameter scope");
     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
     return;
   }
-  scope = json_string_value(cache_object);
-
-  //RECOMMENDED value: state
-  cache_object = json_object_get (root, OIDC_STATE_KEY);
-  if( NULL!=cache_object || json_is_string(cache_object))
-  {
-    state = json_string_value(cache_object);
-  }
+  handle->oidc->scope = json_string_value (cache_object);
+  handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
 
   //OPTIONAL value: nonce
-  cache_object = json_object_get (root, OIDC_NONCE_KEY);
-  if( NULL!=cache_object || json_is_string(cache_object))
+  cache_object = json_object_get (handle->oidc->post_object, OIDC_NONCE_KEY);
+  if ( NULL != cache_object && json_is_string(cache_object) )
   {
-    nonce = json_string_value(cache_object);
+    handle->oidc->nonce = json_string_value (cache_object);
+    //TODO: what do we do with the nonce?
+    handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
   }
 
   //TODO check other values and use them accordingly
   number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
   for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
   {
-    cache_object = json_object_get (root, OIDC_ignored_parameter_array[iterator]);
-    if(json_is_string(cache_object))
+    cache_object = json_object_get (handle->oidc->post_object, OIDC_ignored_parameter_array[iterator]);
+    if( NULL != cache_object && json_is_string(cache_object) )
     {
       handle->emsg=GNUNET_strdup("access_denied");
       GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
@@ -1625,7 +1920,7 @@ authorize_post_cont (struct GNUNET_REST_RequestHandle *con_handle,
   }
 
   // Checks if response_type is 'code'
-  if( 0 != strcmp( response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
+  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 "
@@ -1633,126 +1928,114 @@ authorize_post_cont (struct GNUNET_REST_RequestHandle *con_handle,
     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
     return;
   }
+
   // Checks if scope contains 'openid'
-  if( NULL == strstr( scope, OIDC_EXPECTED_AUTHORIZATION_SCOPE ) )
+  expected_scope = GNUNET_strdup(handle->oidc->scope);
+  expected_scope = strtok (expected_scope, delimiter);
+  while (NULL != expected_scope)
+  {
+    if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
+    {
+      break;
+    }
+    expected_scope = strtok (NULL, delimiter);
+  }
+  if (NULL == expected_scope)
   {
-    handle->emsg=GNUNET_strdup("invalid_scope");
+    handle->emsg = GNUNET_strdup("invalid_scope");
     handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
                                "malformed.");
     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
     return;
   }
 
+  GNUNET_free(expected_scope);
 
-  GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
-                     &cache_key);
-  //No identity-cookie -> redirect to login
-  if ( GNUNET_YES
-      == GNUNET_CONTAINER_multihashmap_contains (con_handle->header_param_map,
-                                                &cache_key) )
+  if( NULL != handle->oidc->login_identity )
   {
-    //split cookies and find 'Identity' cookie
-    char* cookies = GNUNET_CONTAINER_multihashmap_get (
-       con_handle->header_param_map, &cache_key);
-    char delimiter[] = "; ";
-    char *identity_cookie;
-    identity_cookie = strtok(cookies, delimiter);
-
-    while ( NULL != identity_cookie )
-    {
-      if ( NULL != strstr (identity_cookie, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
-      {
-       break;
-      }
-      identity_cookie = strtok (NULL, delimiter);
-    }
-    GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
-
-    //No login time for identity -> redirect to login
-    if ( GNUNET_YES
-       == GNUNET_CONTAINER_multihashmap_contains (OIDC_authorized_identities,
-                                                  &cache_key) )
-    {
-      relog_time = GNUNET_CONTAINER_multihashmap_get (
-             OIDC_authorized_identities, &cache_key);
-
-      current_time = GNUNET_TIME_absolute_get();
-
-      GNUNET_CONTAINER_multihashmap_remove_all(OIDC_authorized_identities, &cache_key);
-      // 30 min after old login -> redirect to login
-      if ( current_time.abs_value_us <= relog_time->abs_value_us )
-      {
-       resp = GNUNET_REST_create_response ("");
+    GNUNET_SCHEDULER_add_now(&login_check,handle);
+    return;
+  }
 
-       GNUNET_CRYPTO_ecdsa_public_key_from_string (identity_cookie,
-                                                   strlen (identity_cookie),
-                                                   &pubkey);
+  GNUNET_SCHEDULER_add_now(&login_redirection,handle);
+}
 
-       // iterate over egos and compare their public key
-//     GNUNET_IDENTITY_PROVIDER_get_attributes_start
-       // iterate over scope variables
-       char delimiter[] = " ";
-       char *scope_attribute;
-       scope_attribute = strtok(scope, delimiter);
 
-       while ( NULL != scope_attribute )
-       {
-         if ( NULL == strstr (scope_attribute, OIDC_EXPECTED_AUTHORIZATION_SCOPE) )
-         {
-           // claim attribute from ego
-           scope_attribute = strtok (NULL, delimiter);
-         }
-       }
-       // create an authorization code
+/**
+ * Responds to authorization POST request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+static void
+authorize_POST_cont (struct GNUNET_REST_RequestHandle *con_handle,
+                const char* url,
+                void *cls)
+{
+  struct RequestHandle *handle = cls;
+  json_t *cache_object;
+  json_error_t error;
+  handle->oidc->post_object = json_loads (handle->rest_handle->data, 0, &error);
 
-//     GNUNET_IDENTITY_PROVIDER_t
+  //gets identity of login try with cookie
+  cookie_identity_interpretation(handle);
 
-       MHD_add_response_header (resp, "Location", redirect_uri);
-       handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
-       cleanup_handle (handle);
-       GNUNET_free(relog_time);
-       return;
-      }
-      GNUNET_free(relog_time);
-    }
+  //RECOMMENDED value: state - REQUIRED for answers
+  cache_object = json_object_get (handle->oidc->post_object, OIDC_STATE_KEY);
+  if ( NULL != cache_object && json_is_string(cache_object) )
+  {
+    handle->oidc->state = json_string_value (cache_object);
+    handle->oidc->state = GNUNET_strdup(handle->oidc->state);
   }
 
+  // REQUIRED value: client_id
+  cache_object = json_object_get (handle->oidc->post_object,
+                                 OIDC_CLIENT_ID_KEY);
+  if ( NULL == cache_object || !json_is_string(cache_object) )
+  {
+    handle->emsg = GNUNET_strdup("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 = json_string_value (cache_object);
+  handle->oidc->client_id = GNUNET_strdup(handle->oidc->client_id);
 
-  // login redirection
   if ( GNUNET_OK
-      == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
-                                               "address", &login_base_url) )
+      != GNUNET_CRYPTO_ecdsa_public_key_from_string (
+         handle->oidc->client_id, strlen (handle->oidc->client_id),
+         &handle->oidc->client_pkey) )
   {
-    GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
-                    login_base_url,
-                    OIDC_RESPONSE_TYPE_KEY,
-                    response_type,
-                    OIDC_CLIENT_ID_KEY,
-                    client_id,
-                    OIDC_REDIRECT_URI_KEY,
-                    redirect_uri,
-                    OIDC_SCOPE_KEY,
-                    scope,
-                    OIDC_STATE_KEY,
-                    (NULL == state) ? state : "",
-                    OIDC_NONCE_KEY,
-                    (NULL == nonce) ? nonce : "");
-    resp = GNUNET_REST_create_response ("");
-    MHD_add_response_header (resp, "Location", new_redirect);
+    handle->emsg = GNUNET_strdup("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;
   }
-  else
+
+  if ( NULL == handle->ego_head )
   {
-    handle->emsg = GNUNET_strdup("No server configuration");
+    //TODO throw error or ignore if egos are missing?
+    handle->emsg = GNUNET_strdup("server_error");
+    handle->edesc = GNUNET_strdup ("Egos are missing");
     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);
-  cleanup_handle (handle);
-  GNUNET_free(new_redirect);
-  return;
-}
 
+  handle->ego_entry = handle->ego_head;
+  handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
+  handle->oidc->is_client_trusted = GNUNET_NO;
+
+  // Checks if client_id is valid:
+  handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
+      handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
+      handle, &namestore_iteration_callback, handle,
+      &namestore_iteration_finished_POST, handle);
+}
 
 /**
  * Combines an identity with a login time and responds OK to login request
@@ -1766,12 +2049,11 @@ login_cont (struct GNUNET_REST_RequestHandle *con_handle,
             const char* url,
             void *cls)
 {
-
-
   struct MHD_Response *resp = GNUNET_REST_create_response ("");
   struct RequestHandle *handle = cls;
   struct GNUNET_HashCode cache_key;
   struct GNUNET_TIME_Absolute *current_time;
+  struct GNUNET_TIME_Absolute *last_time;
   char* cookie;
   json_t *root;
   json_error_t error;
@@ -1783,12 +2065,18 @@ login_cont (struct GNUNET_REST_RequestHandle *con_handle,
     GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
 
     GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
+
     current_time = GNUNET_new(struct GNUNET_TIME_Absolute);
     *current_time = GNUNET_TIME_relative_to_absolute (
        GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_minute_ (),
                                       30));
+    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_authorized_identities, &cache_key, current_time,
+       OIDC_identity_login_time, &cache_key, current_time,
        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
 
     handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
@@ -1799,10 +2087,115 @@ login_cont (struct GNUNET_REST_RequestHandle *con_handle,
   }
   GNUNET_free(cookie);
   json_decref (root);
-  cleanup_handle (handle);
+  GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
   return;
 }
 
+static void
+token_cont(struct GNUNET_REST_RequestHandle *con_handle,
+                const char* url,
+                void *cls)
+{
+  //TODO static strings
+  struct RequestHandle *handle = cls;
+  struct GNUNET_HashCode cache_key;
+  char *authorization, *cache_authorization, *jwt;
+  char delimiter[]=" ";
+  json_t *cache_object;
+  json_error_t error;
+  char *grant_type, *code, *expected_jwt, *redirect_uri, *expected_redirect_uri;
+
+  handle->oidc->post_object = json_loads (handle->rest_handle->data, 0, &error);
+  //Check Authorization Header
+  GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
+                     &cache_key);
+  if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
+                                                            &cache_key) )
+  {
+    //error
+  }
+  authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
+  //split JWT in "Base" and [content]
+  cache_authorization = GNUNET_strdup (authorization);
+  jwt = strtok(cache_authorization,delimiter);
+  if( NULL != jwt)
+  {
+    jwt = strtok(jwt, delimiter);
+    GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Test:%s\n", jwt);
+  }
+
+  cache_object = json_object_get (handle->oidc->post_object, "grant_type");
+  if ( NULL == cache_object || !json_is_string(cache_object) )
+  {
+    handle->emsg=GNUNET_strdup("invalid_request");
+    handle->edesc=GNUNET_strdup("missing parameter grant_type");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  grant_type = json_string_value (cache_object);
+
+  //Check parameter grant_type == "authorization_code"
+  if (0 != strcmp("authorization_code", grant_type))
+  {
+    //error
+  }
+
+  cache_object = json_object_get (handle->oidc->post_object, "code");
+  if ( NULL == cache_object || !json_is_string(cache_object) )
+  {
+    handle->emsg=GNUNET_strdup("invalid_request");
+    handle->edesc=GNUNET_strdup("missing parameter code");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  code = json_string_value (cache_object);
+
+  // lookup code in grants_hashmap and check if [content] is same
+  GNUNET_CRYPTO_hash(code, strlen(code), &cache_key);
+  if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_grants, &cache_key) )
+  {
+    //error
+  }
+  expected_jwt = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_grants, &cache_key);
+
+  if (0 != strcmp(expected_jwt,jwt))
+  {
+    //error
+  }
+
+  cache_object = json_object_get (handle->oidc->post_object, "redirect_uri");
+  if ( NULL == cache_object || !json_is_string(cache_object) )
+  {
+    handle->emsg=GNUNET_strdup("invalid_request");
+    handle->edesc=GNUNET_strdup("missing parameter code");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  redirect_uri = json_string_value (cache_object);
+
+  // check redirect_uri
+  // jwt breakdown to iss or sub
+
+//  GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", iss);
+//  // verify the redirect uri matches https://<client_id>.zkey[/xyz]
+//  if( 0 != strncmp( expected_redirect_uri, redirect_uri, strlen(expected_redirect_uri)) )
+//  {
+//    handle->emsg=GNUNET_strdup("invalid_request");
+//    handle->edesc=GNUNET_strdup("Invalid redirect_uri");
+//    GNUNET_SCHEDULER_add_now (&do_error, handle);
+//    GNUNET_free(expected_redirect_uri);
+//    return;
+//  }
+//  handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
+//  GNUNET_free(expected_redirect_uri);
+
+
+  //do we need the client_id?
+
+  GNUNET_free(cache_authorization);
+  decref(handle->oidc->post_object);
+}
+
 /**
  * Handle rest request
  *
@@ -1816,9 +2209,10 @@ init_cont (struct RequestHandle *handle)
     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
-    {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_get_cont},
+    {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_GET_cont},
+    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_POST_cont},
     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
-    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_post_cont},
+    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_cont},
     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
@@ -1903,11 +2297,12 @@ rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
                               void *proc_cls)
 {
   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
-  if ( NULL == OIDC_authorized_identities )
-  {
-    OIDC_authorized_identities = GNUNET_CONTAINER_multihashmap_create (10,
-                                                                    GNUNET_NO);
-  }
+  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 )
+    OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
+  handle->response_code = 0;
   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
   handle->proc_cls = proc_cls;
   handle->proc = proc;
@@ -1922,6 +2317,7 @@ rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
                                                      &list_ego,
                                                      handle);
+  handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
   handle->timeout_task =
     GNUNET_SCHEDULER_add_delayed (handle->timeout,
                                   &do_timeout,
@@ -1976,8 +2372,27 @@ libgnunet_plugin_rest_identity_provider_done (void *cls)
 {
   struct GNUNET_REST_Plugin *api = cls;
   struct Plugin *plugin = api->cls;
-
   plugin->cfg = NULL;
+
+  struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
+  void *value = NULL;
+  hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (
+      OIDC_identity_login_time);
+  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);
+  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);
   GNUNET_free_non_null (allow_methods);
   GNUNET_free (api);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,