function handle_distributedinfo()
{
    try {
        global $signing_alg_values_supported, $encryption_alg_values_supported, $encryption_enc_values_supported;
        $token = $_REQUEST['access_token'];
        if (!$token) {
            $token = get_bearer_token();
            if (!$token) {
                throw new BearerException('invalid_request', 'No Access Token');
            }
        }
        // check code
        $token = db_find_access_token($token);
        if (!$token) {
            throw new BearerException('invalid_request', 'Cannot find Access Token');
        }
        $db_client = db_get_client($token['client']);
        if (!$db_client) {
            throw new BearerException('invalid_request', 'Invalid Client ID');
        }
        $tinfo = json_decode($token['info'], true);
        $userinfo = array();
        $persona = db_get_user_persona($tinfo['u'], $tinfo['p'])->toArray();
        $scopes = explode(' ', $tinfo['g']['scope']);
        if (in_array('openid', $scopes)) {
            $userinfo['sub'] = wrap_userid($db_client, $tinfo['u']);
        }
        log_debug("userid = %s unwrapped = %s", $userinfo['sub'], unwrap_userid($userinfo['sub']));
        $requested_userinfo_claims = get_userinfo_claims($tinfo['r'], $tinfo['r']['scope']);
        $persona_custom_claims = db_get_user_persona_custom_claims($tinfo['u'], $tinfo['p']);
        foreach ($persona_custom_claims as $pcc) {
            $persona_claims[$pcc['claim']] = $pcc->PersonaCustomClaim[0]['value'];
        }
        log_debug("ALLOWED CLAIMS = %s", print_r($tinfo['l'], true));
        log_debug("REQUESTED_USER_INFO = %s", print_r($requested_userinfo_claims, true));
        $src = 0;
        foreach ($tinfo['l'] as $key) {
            if (array_key_exists($key, $requested_userinfo_claims)) {
                $prefix = substr($key, 0, 3);
                if ($prefix == 'ax.') {
                    $key = substr($key, 3);
                    $mapped_key = $key;
                    $kana = strpos($key, '_ja_kana_jp');
                    $hani = strpos($key, '_ja_hani_jp');
                    if ($kana !== false) {
                        $mapped_key = substr($key, 0, $kana) . '#ja-Kana-JP';
                    }
                    if ($hani !== false) {
                        $mapped_key = substr($key, 0, $hani) . '#ja-Hani-JP';
                    }
                    switch ($mapped_key) {
                        case 'address':
                            $userinfo[$mapped_key] = array('formatted' => $persona[$key]);
                            break;
                        case 'email_verified':
                        case 'phone_number_verified':
                            if ($persona[$key]) {
                                $userinfo[$mapped_key] = true;
                            } else {
                                $userinfo[$mapped_key] = false;
                            }
                            break;
                        default:
                            $userinfo[$mapped_key] = $persona[$key];
                            break;
                    }
                } elseif ($prefix == 'cx.') {
                    $key = substr($key, 3);
                    $userinfo[$key] = $persona_claims[$key];
                }
            }
        }
        $sig_param = array('alg' => 'none');
        $sig_key = NULL;
        if ($db_client['userinfo_signed_response_alg']) {
            if (in_array($db_client['userinfo_signed_response_alg'], $signing_alg_values_supported)) {
                $sig_param['alg'] = $db_client['userinfo_signed_response_alg'];
                if (substr($db_client['userinfo_signed_response_alg'], 0, 2) == 'HS') {
                    $sig_key = $db_client['client_secret'];
                } elseif (substr($db_client['userinfo_signed_response_alg'], 0, 2) == 'RS') {
                    $sig_param['jku'] = OP_JWK_URL;
                    $sig_param['kid'] = OP_SIG_KID;
                    $sig_key = array('key_file' => OP_SIG_PKEY, 'password' => OP_SIG_PKEY_PASSPHRASE);
                }
                log_debug("DistributedInfo Using Sig Alg %s", $sig_param['alg']);
                $userinfo_jwt = jwt_sign($userinfo, $sig_param, $sig_key);
                if (!$userinfo_jwt) {
                    log_error("Unable to sign response for DistributedInfo");
                    send_bearer_error('400', 'invalid_request', 'Unable to sign response for DistributedInfo');
                }
                if ($db_client['userinfo_encrypted_response_alg'] && $db_client['userinfo_encrypted_response_enc']) {
                    log_debug("UserInfo Encryption Algs %s %s", $db_client['userinfo_encrypted_response_alg'], $db_client['userinfo_encrypted_response_enc']);
                    list($alg, $enc) = array($db_client['userinfo_encrypted_response_alg'], $db_client['userinfo_encrypted_response_enc']);
                    if (in_array($alg, $encryption_alg_values_supported) && in_array($enc, $encryption_enc_values_supported)) {
                        $jwk_uri = '';
                        $encryption_keys = NULL;
                        if ($db_client['jwks_uri']) {
                            $jwk = get_url($db_client['jwks_uri']);
                            if ($jwk) {
                                $jwk_uri = $db_client['jwks_uri'];
                                $encryption_keys = jwk_get_keys($jwk, 'RSA', 'enc', NULL);
                                if (!$encryption_keys || !count($encryption_keys)) {
                                    $jwk_uri = NULL;
                                    if (!empty($db_client['jwks'])) {
                                        $encryption_keys = jwk_get_keys($db_client['jwks'], 'RSA', 'enc', NULL);
                                    }
                                    if (!$encryption_keys || !count($encryption_keys)) {
                                        $encryption_keys = NULL;
                                    }
                                }
                            }
                        }
                        if (!$encryption_keys) {
                            send_bearer_error('400', 'invalid_request', 'Unable to retrieve JWK key for encryption');
                        }
                        if ($jwk_uri) {
                            $header_params = array('jku' => $jwk_uri);
                        }
                        if (isset($encryption_keys[0]['kid'])) {
                            $header_params['kid'] = $encryption_keys[0]['kid'];
                        }
                        $userinfo_jwt = jwt_encrypt2($userinfo_jwt, $encryption_keys[0], false, NULL, $header_params, NULL, $alg, $enc, false);
                        if (!$userinfo_jwt) {
                            log_error("Unable to encrypt response for DistributedInfo");
                            send_bearer_error('400', 'invalid_request', 'Unable to encrypt response for DistributedInfo');
                        }
                    } else {
                        log_error("UserInfo Encryption Algs %s and %s not supported", $alg, $enc);
                        send_bearer_error('400', 'invalid_request', 'Client registered unsupported encryption algs for UserInfo');
                    }
                }
                header("Content-Type: application/jwt");
                header("Cache-Control: no-store");
                header("Pragma: no-cache");
                log_debug('DistributedInfo response = %s', $userinfo_jwt);
                echo $userinfo_jwt;
            } else {
                log_error("UserInfo Sig Alg %s not supported", $db_client['userinfo_signed_response_alg']);
                send_bearer_error('400', 'invalid_request', "UserInfo Sig Alg {$db_client['userinfo_signed_response_alg']} not supported");
            }
        } else {
            header("Cache-Control: no-store");
            header("Pragma: no-cache");
            header("Content-Type: application/json");
            log_debug('DistributedInfo response = %s', json_encode($userinfo));
            echo json_encode($userinfo);
        }
    } catch (BearerException $e) {
        send_bearer_error('401', $e->error_code, $e->desc);
    } catch (OidcException $e) {
        send_error('', $e->error_code, $e->desc);
    }
}
function webrtc_handle_auth()
{
    $state = isset($_REQUEST['state']) ? $_REQUEST['state'] : NULL;
    $error_page = OP_INDEX_PAGE;
    $response_mode = 'query';
    try {
        if (!isset($_REQUEST['client_id'])) {
            throw new OidcException('invalid_request', 'no client');
        }
        // check client id
        $client = db_get_client($_REQUEST['client_id']);
        if (!$client) {
            throw new OidcException('unauthorized_client', 'Client ID not found');
        }
        /*        if(isset($_REQUEST['redirect_uri'])) {
                    if(!is_valid_registered_redirect_uri($client['redirect_uris'], $_REQUEST['redirect_uri']))
                        throw new OidcException('invalid_request', 'no matching redirect_uri');
                } else
                    throw new OidcException('invalid_request', 'no redirect_uri in request');
        
                $error_page = $_REQUEST['redirect_uri'];
        */
        $response_mode = get_response_mode($_REQUEST);
        if (!isset($_REQUEST['response_type'])) {
            throw new OidcException('invalid_request', 'no response_type');
        }
        $response_types = explode(' ', $_REQUEST['response_type']);
        $known_response_types = array('code', 'token', 'id_token');
        if (count(array_diff($response_types, $known_response_types))) {
            throw new OidcException('invalid_response_type', "Unknown response_type {$_REQUEST['response_type']}");
        }
        if (ENABLE_PKCE) {
            if (in_array('code', $response_types)) {
                if (!isset($_REQUEST['code_challenge'])) {
                    throw new OidcException('invalid_request', 'code challenge required');
                }
                if (isset($_REQUEST['code_challenge_method'])) {
                    if (!in_array($_REQUEST['code_challenge_method'], array('plain', 'S256'))) {
                        throw new OidcException('invalid_request', "unsupported code challenge method {$_REQUEST['code_challenge_method']}");
                    }
                }
            }
        }
        if (!isset($_REQUEST['scope'])) {
            throw new OidcException('invalid_request', 'no scope');
        }
        $scopes = explode(' ', $_REQUEST['scope']);
        if (!in_array('openid', $scopes)) {
            throw new OidcException('invalid_scope', 'no openid scope');
        }
        if (in_array('token', $response_types) || in_array('id_token', $response_types)) {
            if (!isset($_REQUEST['nonce'])) {
                throw new OidcException('invalid_request', 'no nonce');
            }
        }
        $_SESSION['get'] = $_GET;
        $request_uri = isset($_REQUEST['request_uri']) ? $_REQUEST['request_uri'] : NULL;
        $requested_userid = NULL;
        $requested_userid_display = NULL;
        $request_object = NULL;
        if ($request_uri) {
            $request_object = get_url($request_uri);
            if (!$request_object) {
                throw new OidcException('invalid_request', "Unable to fetch request file {$request_uri}");
            }
        } elseif (isset($_REQUEST['request'])) {
            $request_object = $_REQUEST['request'];
        }
        if (isset($_GET['claims'])) {
            $_GET['claims'] = json_decode($_GET['claims'], true);
            $_REQUEST['claims'] = $_GET['claims'];
        }
        if (isset($request_object)) {
            $cryptoError = '';
            $payload = decrypt_verify_jwt($request_object, $client, $cryptoError);
            if (!isset($payload)) {
                if ($cryptoError == 'error_decrypt') {
                    throw new OidcException('invalid_request', 'Unable to decrypt request object');
                } elseif ($cryptoError == 'error_sig') {
                    throw new OidcException('invalid_request', 'Unable to verify request object signature');
                }
            } else {
                if (isset($payload['claims']['id_token'])) {
                    if (array_key_exists('sub', $payload['claims']['id_token']) && isset($payload['claims']['id_token']['sub']['value'])) {
                        $requested_userid_display = $payload['claims']['id_token']['sub']['value'];
                        $requested_userid = unwrap_userid($payload['claims']['id_token']['sub']['value']);
                        if (!db_get_user($requested_userid)) {
                            throw new OidcException('invalid_request', 'Unrecognized userid in request');
                        }
                    }
                }
                $merged_req = array_merge($_GET, $payload);
                if (!array_key_exists('max_age', $merged_req) && $client['default_max_age']) {
                    $merged_req['max_age'] = $client['default_max_age'];
                }
                if ($merged_req['max_age']) {
                    $merged_req['claims']['id_token']['auth_time'] = array('essential' => true);
                }
                if ((!$merged_req['claims']['id_token'] || !array_key_exists('auth_time', $merged_req['claims']['id_token'])) && $client['require_auth_time']) {
                    $merged_req['claims']['id_token']['auth_time'] = array('essential' => true);
                }
                if (!$merged_req['claims']['id_token'] || !array_key_exists('acr', $merged_req['claims']['id_token'])) {
                    if ($merged_req['acr_values']) {
                        $merged_req['claims']['id_token']['acr'] = array('essential' => true, 'values' => explode(' ', $merged_req['acr_values']));
                    } elseif ($client['default_acr_values']) {
                        $merged_req['claims']['id_token']['acr'] = array('essential' => true, 'values' => explode('|', $client['default_acr_values']));
                    }
                }
                $_SESSION['rpfA'] = $merged_req;
                log_debug("rpfA = %s", print_r($_SESSION['rpfA'], true));
                foreach (array('client_id', 'response_type', 'scope', 'nonce', 'redirect_uri') as $key) {
                    if (!isset($payload[$key])) {
                        log_error("missing %s in payload => %s", $key, print_r($payload, true));
                    }
                    //                      throw new OidcException('invalid_request', 'Request Object missing required parameters');
                }
                log_debug("payload => %s", print_r($payload, true));
                foreach ($payload as $key => $value) {
                    if (isset($_REQUEST[$key]) && strcmp($_REQUEST[$key], $value)) {
                        log_debug("key : %s value:%s", $key, print_r($value, true));
                        throw new OidcException('invalid_request', "Request Object Param Values do not match request '{$key}' '{$_REQUEST[$key]}' != '{$value}'");
                    }
                }
            }
        } else {
            if (isset($_GET['id_token_hint'])) {
                $cryptoError = '';
                $payload = decrypt_verify_jwt($_REQUEST['id_token_hint'], $client, $cryptoError);
                if (!isset($payload)) {
                    if ($cryptoError == 'error_decrypt') {
                        throw new OidcException('invalid_request', 'Unable to decrypt request object');
                    } elseif ($cryptoError == 'error_sig') {
                        throw new OidcException('invalid_request', 'Unable to verify request object signature');
                    }
                } else {
                    $requested_userid_display = $payload['sub'];
                    $requested_userid = unwrap_userid($payload['sub']);
                    if (!db_get_user($requested_userid)) {
                        throw new OidcException('invalid_request', 'Unrecognized userid in ID Token');
                    }
                }
            } else {
                if (isset($_GET['claims']['id_token']['sub']['value'])) {
                    $requested_userid_display = $_GET['claims']['id_token']['sub']['value'];
                    $requested_userid = unwrap_userid($_GET['claims']['id_token']['sub']['value']);
                    if (!db_get_user($requested_userid)) {
                        throw new OidcException('invalid_request', "Unrecognized userid in ID Token");
                    }
                } else {
                    if (isset($_GET['login_hint'])) {
                        $principal = $_GET['login_hint'];
                        $at = strpos($principal, '@');
                        if ($at !== false) {
                            error_log("EMAIL\n");
                            if ($at != 0) {
                                // XRI
                                // process email address
                                list($principal, $domain) = explode('@', $principal);
                                error_log("==> principal = {$principal} domain = {$domain}");
                                $port_pos = strpos($domain, ':');
                                if ($port_pos !== false) {
                                    $domain = substr($domain, 0, $port_pos);
                                }
                                $domain_parts = explode('.', $domain);
                                $server_parts = explode('.', OP_SERVER_NAME);
                                // check to see domain matches
                                $domain_start = count($domain_parts) - 1;
                                $server_start = count($server_parts) - 1;
                                $domain_match = true;
                                for ($i = $domain_start, $j = $server_start; $i >= 0 && $j >= 0; $i--, $j--) {
                                    if (strcasecmp($domain_parts[$i], $server_parts[$j]) != 0) {
                                        $domain_match = false;
                                    }
                                }
                                if ($domain_match) {
                                    $requested_userid_display = $principal;
                                    $requested_userid = unwrap_userid($requested_userid_display);
                                    if (!db_get_user($requested_userid)) {
                                        $requested_userid_display = NULL;
                                        $requested_userid = NULL;
                                    }
                                } else {
                                    throw new OidcException('invalid_request', 'Unrecognized email domain');
                                }
                            }
                        } else {
                            // name only
                            $requested_userid_display = $_GET['login_hint'];
                            $requested_userid = unwrap_userid($requested_userid_display);
                            if (!db_get_user($requested_userid)) {
                                $requested_userid_display = NULL;
                                $requested_userid = NULL;
                            }
                        }
                    }
                }
            }
            if (!array_key_exists('max_age', $_REQUEST) && $client['default_max_age']) {
                $_REQUEST['max_age'] = $client['default_max_age'];
            }
            if ($_REQUEST['max_age']) {
                $_REQUEST['claims']['id_token']['auth_time'] = array('essential' => true);
            }
            if ((!$_REQUEST['claims']['id_token'] || !array_key_exists('auth_time', $_REQUEST['claims']['id_token'])) && $client['require_auth_time']) {
                $_REQUEST['claims']['id_token']['auth_time'] = array('essential' => true);
            }
            if (!$_REQUEST['claims']['id_token'] || !array_key_exists('acr', $_REQUEST['claims']['id_token'])) {
                if ($_REQUEST['acr_values']) {
                    $_REQUEST['claims']['id_token']['acr'] = array('essential' => true, 'values' => explode(' ', $_REQUEST['acr_values']));
                } elseif ($client['default_acr_values']) {
                    $_REQUEST['claims']['id_token']['acr'] = array('essential' => true, 'values' => explode('|', $client['default_acr_values']));
                }
            }
            $_SESSION['rpfA'] = $_REQUEST;
        }
        log_debug("prompt = %s", $_SESSION['rpfA']['prompt']);
        $prompt = $_SESSION['rpfA']['prompt'] ? explode(' ', $_SESSION['rpfA']['prompt']) : array();
        $num_prompts = count($prompt);
        if ($num_prompts > 1 && in_array('none', $prompt)) {
            throw new OidcException('interaction_required', "conflicting prompt parameters {$_SESSION['rpfA']['prompt']}");
        }
        if (in_array('none', $prompt)) {
            $showUI = false;
        } else {
            $showUI = true;
        }
        log_debug("num prompt = %d %s", $num_prompts, print_r($prompt, true));
        if ($_SESSION['username']) {
            if (in_array('login', $prompt)) {
                echo loginform($requested_userid_display, $requested_userid, $client);
                exit;
            }
            if (isset($_SESSION['rpfA']['max_age'])) {
                if (time() - $_SESSION['auth_time'] > $_SESSION['rpfA']['max_age']) {
                    if (!$showUI) {
                        throw new OidcException('interaction_required', 'max_age exceeded and prompt set to none');
                    }
                    echo loginform($requested_userid_display, $requested_userid, $client);
                    exit;
                }
            }
            if ($requested_userid) {
                if ($_SESSION['username'] != $requested_userid) {
                    if (!$showUI) {
                        //                        throw new OidcException('interaction_required', 'requested account is different from logged in account, no UI requested');
                    } else {
                        //                        echo loginform($requested_userid_display, $requested_userid, $client);
                        exit;
                    }
                }
            }
            // if(in_array('consent', $prompt)){
            // echo confirm_userinfo();
            // exit();
            // }
            if (!db_get_user_trusted_client($_SESSION['username'], $_REQUEST['client_id'])) {
                if (!$showUI) {
                    throw new OidcException('interaction_required', 'consent needed and prompt set to none');
                }
                echo confirm_userinfo();
            } else {
                send_response_noRedirect($_SESSION['username'], true);
            }
        } else {
            // SBE Redirect to auth_time
            send_auth_response($request_uri, array(), $response_mode);
            //	header("Location: /auth?client_id=$client_id&response_type=$_REQUEST['response_type']&scope=$_REQUEST['scope']&nonce=$_REQUEST['nonce']");
            //            if(!$showUI)
            //                throw new OidcException('interaction_required', 'unauthenticated and prompt set to none');
            //            echo custom_loginform($requested_userid_display, $requested_userid, $client);
        }
    } catch (OidcException $e) {
        log_debug("handle_auth exception : %s", $e->getTraceAsString());
        send_error($error_page, $e->error_code, $e->desc, NULL, $state, $response_mode);
    } catch (Exception $e) {
        log_debug("handle_auth exception : %s", $e->getTraceAsString());
        send_error($error_page, 'invalid_request', $e->getMessage(), NULL, $state, $response_mode);
    }
}