}
# Sort out the grant tokens
$grant_token = api_oauth2_grant_tokens_get_by_code($code);
if ($ok && !$grant_token) {
    $error = "invalid_grant 1";
    $ok = 0;
}
if ($ok && $grant_token['code'] != $code) {
    $error = "invalid_grant 2";
    $ok = 0;
}
if ($ok && $grant_token['api_key_id'] != $key_row['id']) {
    $error = "invalid_client 3";
    $ok = 0;
}
if ($ok && !api_oauth2_grant_tokens_is_timely($grant_token)) {
    $error = "invalid_grant 4";
    $ok = 0;
}
if ($ok) {
    $user = users_get_by_id($grant_token['user_id']);
    if (!$user || $user['deleted']) {
        $error = "invalid_request 5";
        $ok = 0;
    }
}
if (!$ok) {
    $rsp = array('error' => $error);
    local_send_json($rsp);
    exit;
}
    $ok = 0;
}
if ($ok && request_str("redirect_uri") != $key_row['app_callback']) {
    $GLOBALS['smarty']->assign("error", "invalid_callback");
    $ok = 0;
}
if ($ok && request_str("response_type") != "code") {
    $GLOBALS['smarty']->assign("error", "invalid_type");
    $ok = 0;
}
# Do we already have a grant token for this user?
# And yes this is a repeat of the code below that should maybe be
# moved in to a function or something. But for now it's fine...
# (20121024/straup)
if ($ok && ($token = api_oauth2_grant_tokens_get_for_user_and_key($GLOBALS['cfg']['user'], $key_row))) {
    if (api_oauth2_grant_tokens_is_timely($token)) {
        $rsp_params = array('code' => $token['code']);
        if ($state = get_str("state")) {
            $rsp_params['state'] = $state;
        }
        $rsp_params = http_build_query($rsp_params);
        $url = $key_row['app_callback'] . "?" . $rsp_params;
        header("location: {$url}");
        exit;
    } else {
        api_oauth2_grant_tokens_delete($token);
    }
}
# Do we already have an access token (with the same perms) for this user?
if ($ok && ($token_row = api_oauth2_access_tokens_get_for_user_and_key($GLOBALS['cfg']['user'], $key_row))) {
    $perms_map = api_oauth2_access_tokens_permissions_map("string keys");