function send_response($username, $authorize = false)
{
    $GET = $_SESSION['get'];
    $rpfA = $_SESSION['rpfA'];
    $rpep = $GET['redirect_uri'];
    $state = isset($GET['state']) ? $GET['state'] : NULL;
    $error_page = isset($GET['redirect_uri']) ? $GET['redirect_uri'] : OP_INDEX_PAGE;
    $response_mode = get_response_mode($GET);
    try {
        $client_id = $GET['client_id'];
        $response_types = explode(' ', $GET['response_type']);
        $scopes = explode(' ', $GET['scope']);
        $prompts = explode(' ', $GET['prompt']);
        $is_code_flow = in_array('code', $response_types);
        $is_token_flow = in_array('token', $response_types);
        $is_id_token = in_array('id_token', $response_types);
        $offline_access = $is_code_flow && !$is_token_flow && in_array('consent', $prompts) && in_array('offline_access', $scopes);
        $issue_at = strftime('%G-%m-%d %T');
        $expiration_at = strftime('%G-%m-%d %T', time() + 2 * 60);
        $response_params = array();
        if (!$authorize) {
            throw new OidcException('access_denied', 'User denied access');
        }
        $rpfA['session_id'] = session_id();
        $rpfA['auth_time'] = $_SESSION['auth_time'];
        $confirmed_attribute_list = get_all_requested_claims($rpfA, $GET['scope']);
        if ($is_code_flow) {
            $code_info = create_token_info($username, $confirmed_attribute_list, $GET, $rpfA);
            $code = $code_info['name'];
            unset($code_info['name']);
            $fields = array('client' => $GET['client_id'], 'issued_at' => $issue_at, 'expiration_at' => $expiration_at, 'token' => $code, 'details' => '', 'token_type' => TOKEN_TYPE_AUTH_CODE, 'info' => json_encode($code_info));
            db_save_user_token($username, $code, $fields);
        }
        if ($is_token_flow) {
            $code_info = create_token_info($username, $confirmed_attribute_list, $GET, $rpfA);
            $token = $code_info['name'];
            unset($code_info['name']);
            $issue_at = strftime('%G-%m-%d %T');
            $expiration_at = strftime('%G-%m-%d %T', time() + 2 * 60);
            $fields = array('client' => $GET['client_id'], 'issued_at' => $issue_at, 'expiration_at' => $expiration_at, 'token' => $token, 'details' => '', 'token_type' => TOKEN_TYPE_ACCESS, 'info' => json_encode($code_info));
            db_save_user_token($username, $token, $fields);
        }
        if ($offline_access) {
            while (true) {
                $refresh_token_name = base64url_encode(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
                if (!db_find_token($refresh_token_name)) {
                    break;
                }
            }
            $fields = array('client' => $GET['client_id'], 'issued_at' => $issue_at, 'expiration_at' => $expiration_at, 'token' => $refresh_token_name, 'details' => '', 'token_type' => TOKEN_TYPE_REFRESH, 'info' => json_encode($code_info));
            $fields['expiration_at'] = strftime('%G-%m-%d %T', time() + 24 * 60 * 60);
            db_save_user_token($username, $refresh_token_name, $fields);
        }
        // Handle response_type for code or token
        if (isset($GET['state'])) {
            $response_params['state'] = $GET['state'];
        }
        if ($is_token_flow || $is_id_token) {
            if (isset($token)) {
                $response_params['access_token'] = $token;
                $response_params['token_type'] = 'Bearer';
                if ($offline_access) {
                    $response_params['refresh_token'] = $refresh_token_name;
                }
                $response_params['expires_in'] = '3600';
            }
        }
        if ($is_id_token) {
            $client_secret = null;
            $nonce = isset($GET['nonce']) ? $GET['nonce'] : null;
            $c_hash = null;
            $at_hash = null;
            $ops = null;
            $auth_time = null;
            $acr = null;
            $idt_claims = array();
            $sig = null;
            $alg = null;
            $enc = null;
            $client_secret = null;
            $jwk_uri = null;
            $db_client = db_get_client($client_id);
            if ($db_client) {
                $sig = $db_client['id_token_signed_response_alg'];
                if (!isset($sig)) {
                    $sig = 'RS256';
                }
                $alg = $db_client['id_token_encrypted_response_alg'];
                $enc = $db_client['id_token_encrypted_response_enc'];
                $client_secret = $db_client['client_secret'];
                $jwk_uri = $db_client['jwks_uri'];
                $jwks = $db_client['jwks'];
            }
            if (isset($rpfA['claims']) && isset($rpfA['claims']['id_token'])) {
                if (array_key_exists('auth_time', $rpfA['claims']['id_token'])) {
                    $auth_time = (int) $_SESSION['auth_time'];
                }
                if (array_key_exists('acr', $rpfA['claims']['id_token'])) {
                    if (array_key_exists('values', $rpfA['claims']['id_token']['acr'])) {
                        if (is_array($rpfA['claims']['id_token']['acr']['values']) && count($rpfA['claims']['id_token']['acr']['values'])) {
                            $acr = $rpfA['claims']['id_token']['acr']['values'][0];
                        }
                    } else {
                        $acr = '0';
                    }
                }
            }
            if ($sig) {
                $bit_length = substr($sig, 2);
                switch ($bit_length) {
                    case '384':
                        $hash_alg = 'sha384';
                        break;
                    case '512':
                        $hash_alg = 'sha512';
                        break;
                    case '256':
                    default:
                        $hash_alg = 'sha256';
                        break;
                }
                $hash_length = (int) ((int) $bit_length / 2) / 8;
                if ($code) {
                    $c_hash = base64url_encode(substr(hash($hash_alg, $code, true), 0, $hash_length));
                }
                if ($token) {
                    $at_hash = base64url_encode(substr(hash($hash_alg, $token, true), 0, $hash_length));
                }
            }
            $requested_id_token_claims = get_id_token_claims($rpfA);
            if ($requested_id_token_claims) {
                $db_user = db_get_user($username);
                if ($db_user) {
                    $idt_claims = get_account_claims($db_user, $requested_id_token_claims);
                } else {
                    throw new OidcException('access_denied', 'no such user');
                }
            }
            $id_token_obj = make_id_token(wrap_userid($db_client, $username), SERVER_ID, $client_id, $idt_claims, $nonce, $c_hash, $at_hash, $auth_time, $ops, $acr);
            log_debug('sen_response id_token_obj = %s', print_r($id_token_obj, true));
            $cryptoError = null;
            $id_token = sign_encrypt($id_token_obj, $sig, $alg, $enc, $jwk_uri, $jwks, $client_secret, $cryptoError);
            if (!$id_token) {
                log_error("Unable to sign encrypt response for ID Token %s", $cryptoError);
                throw new OidcException('invalid_request', "idtoken crypto error {$cryptoError}");
            }
            $response_params['id_token'] = $id_token;
        }
        $url_parts = parse_url($rpep);
        $origin = sprintf("%s://%s%s", $url_parts['scheme'], $url_parts['host'], isset($url_parts['port']) ? ':' . $url_parts['port'] : '');
        $salt = bin2hex(mcrypt_create_iv(16, MCRYPT_DEV_URANDOM));
        log_debug("ss = sha256(%s%s%s%s).%s", $client_id, $origin, $_SESSION['ops'], $salt, $salt);
        $session_state = hash('sha256', "{$client_id}{$origin}{$_SESSION['ops']}{$salt}") . '.' . $salt;
        $response_params['session_state'] = $session_state;
        if ($is_code_flow) {
            $response_params['code'] = $code;
        }
        if ($_SESSION['persist'] == 'on') {
            $username = $_SESSION['username'];
            $auth_time = $_SESSION['auth_time'];
            $ops = $_SESSION['ops'];
            $login = $_SESSION['login'];
            clean_session();
            $_SESSION['lastlogin'] = time();
            $_SESSION['username'] = $username;
            $_SESSION['auth_time'] = $auth_time;
            $_SESSION['ops'] = $ops;
            $_SESSION['login'] = $login;
            $_SESSION['persist'] = 'on';
        } else {
            session_destroy();
        }
        send_auth_response($rpep, $response_params, $response_mode);
    } catch (OidcException $e) {
        log_error("handle_auth exception : %s", $e->getTraceAsString());
        send_error($error_page, $e->error_code, $e->desc, NULL, $state, $response_mode);
    } catch (Exception $e) {
        log_error("handle_auth exception : %s", $e->getTraceAsString());
        send_error($error_page, 'invalid_request', $e->getMessage(), NULL, $state, $response_mode);
    }
}
function db_delete_client($name)
{
    $client = db_get_client($name);
    if ($client) {
        $client->Logs->delete();
        $client->delete();
    }
}