Currently, for authentication for my Facebook App, I'm doing the following in PHP:
if($_GET["code"] == null)
{
Header("Location: https://graph.facebook.com/oauth/authorize?
client_id=[MY_APP_ID]&
redirect_uri=[THIS_CURRENT_URL]&
scope=publish_stream");
exit();
}
else if($_GET["access_token"] == null)
{
$code = $_GET["code"];
Header("Location: https://graph.facebook.com/oauth/access_token?
client_id=[MY_APP_ID]&
redirect_uri=[THIS_CURRENT_URL]&
client_secret=[MY_APP_SECRET]&
code=$code");
exit();
}
else
{
echo($_GET["access_token"]);
}
Is this safe/proper? Couldn't a malicious user just "intercept" the redirects and see my App ID and App Secret?
This is the textbook definition of unsafe. The Location: header, like all headers, is sent to the user's browser, with the explicit purpose of making that data known to the user's browser. The content of the header will be available to any user running a debugging proxy (like Charles or FireBug) and, I strongly suspect, in the browser's address bar as well.
It's perfectly acceptable to send data this way if the user is allowed to see that data (this is often the case for single sign on applications), but the application secret is almost certainly not acceptable.
Consider using curl for connecting directly to the Facebook server instead.
Related
I'm trying to implement Sign In with Apple workflow on a backend server, for all those devices that do not support it natively.
I've tried both with and without 3rd party libraries. Right now I'm using patrickbussmann/oauth2-apple.
I successfully authorize the account through the authorization URL, but the redirect URL have no fields (especially the 'code' one).
This is how I generate the authorization URL:
function get_apple_signin_url() {
$options = [
'scope' => ['email'],
];
$authUrl = $this->provider->getAuthorizationUrl($options);
$_SESSION['oauth2state'] = $this->provider->getState();
return '{"url": "'.$authUrl.'"}';
}
The URL obtained is correct and it works utill the end of login:
https://appleid.apple.com/auth/authorize?scope=email&state=a9583c14408af68ac05cbfed3a8274ef&response_type=code&approval_prompt=auto&redirect_uri=MY_REDIRECT_URI&client_id=MY_CLIENT_ID&response_mode=form_post
This is the code inside the redirect uri (apple_auth_redirect.php):
<?php
if (isset($_POST['code'])) {
$code = urlencode($_POST['code']);
header("Location: intent://callback?apple_id_token=".$code);
} else {
echo "no_code";
}
As you can see from the authorization URL, the response_mode is form_post. If I use query as response_mode I obtain the code, but I cannot insert email as scope. More details in response_mode at Incorporating Sign in with Apple into Other Platforms (developer.apple.com).
This is the current authorization workflow I've implemented:
Mobile app calls get_apple_signin_url on the server.
Mobile app opens the url in the browser.
The authorization through Apple website is completed and the browser is redirected to redirect uri apple_auth_redirect.php.
The code should be parsed by apple_auth_redirect.php but the redirect request has no fields.
I've implemented the same procedure for Google and Huawei sign in without problems.
I solved the problem. I thought that I wasn't correctly handling the redirect. However, the problem was that I wrote redirect_uri=MY_REDIRECT_URI without "www", just the domain e.g., "my_domain.com". With "www" e.g., "www.my_domain.com", it worked.
I'm authenticating my users and then sending each of them a unique cookie which I will store server side and client side. In order to provide some level of security to my API, I'm sending every request to my api with that cookie.. I set the cookie on IOS like this
let cookie = HTTPCookie(properties: [HTTPCookiePropertyKey.originURL : apiURL, HTTPCookiePropertyKey.name :
cookie_name, HTTPCookiePropertyKey.value : cookie_value, HTTPCookiePropertyKey.path : "/"])
HTTPCookieStorage.shared.setCookie(cookie)
I'm 100% sure that the way I'm setting my cookie up is perfect. I've done it in previous apps... just never with a PHP API on the other end. The only issue is that my PHP API doesn't recognize the cookie...
I'm checking like this:
if($_COOKIE['cookie_name'] != ''){ }
When I try to call the API from Postman (a google chrome extension that allows to pass cookies), it works fine and my php script recognizes the cookie. When I try to make calls from my mobile device, I get unauthorized access everytime because the PHP API fails to recognize that the cookie was passed...
The reason why I'm confident that I'm creating and passing my cookie correctly is because I do it in all of my Ruby on Rails app the same way...
Any advice?
Check like this
let cookie = HTTPCookie(properties: [HTTPCookiePropertyKey.originURL : apiURL, HTTPCookiePropertyKey.name :
cookie_name, HTTPCookiePropertyKey.value : cookie_value, HTTPCookiePropertyKey.path : "/"])
HTTPCookieStorage.shared.setCookie(cookie)
if($_COOKIE['cookie'] != ''){ }
the name of the cookie is not cookie name it's cookie as the line below
// (cookie) = cookie name
HTTPCookieStorage.shared.setCookie(cookie)
so this is how you should check
if($_COOKIE['cookie'] != ''){ }
I am currently working on a project that I've decided to go with basic HTTP authorization at the admin area for simplicity, however the company I'm working for already has HTTP authorization on their staging server and I was wondering if it is possible to have double HTTP authorization? Looking at the headers I thought that the realm part is what defines where the user is authorized but if I implement it like that currently, after I enter my credentials for the staging server and then on my inner authorization something that looks like an infinite loop starts, the page never loads.
Is this possible at all or is there some kind of error in my code?
The code is pretty basic stuff:
function require_auth() {
if (!isset($_SESSION['auth'])) {
if ($_SERVER['PHP_AUTH_USER'] === '...' && $_SERVER['PHP_AUTH_PW'] === '...') {
return $_SESSION['auth'] = true;
} else {
header('WWW-Authenticate: Basic realm="uniquerealm"');
header('HTTP/1.0 401 Unauthorized');
}
exit('403 access denied');
}
}
If the HTTP request passes through multiple servers, such as a reverse proxy then an app server, you can use HTTP Basic Auth on each server provided that you accept the same username and password and report the same realm on each server that checks the auth. The realm partitions the URL space that the user sees into different areas, rather than identifying a particular server as I think your question is implying. I've successfully implemented Basic Auth in multiple layers in the past when all 3 pieces matched between servers.
Using python httpx_auth, I successfully passed through two Basic HTTP Authentication with different credentials:
import httpx
from httpx_auth import Basic
with httpx.Client() as client:
a= client.get('https://example.com', auth=Basic('user1', 'password1') + Basic('user2','password2'))
I am trying to authenticate with a family history web service that authenticates using OAuth2. The basic workflow of the authentication is that I submit a get request against the web service requesting an authentication session. It returns in the body of the response HTML Code with some login components for user name and password. My PHP application then echoes the html code to the browser. The end user can then enter his or her user name and password, then submit to the web service. This is where the behavior becomes unclear. In theory, The web service should redirect to a predefined redirect URI with some parameters included in the URL. In practice, however, submitting the password redirects to the pre registered redirect URI, but there are no parameters included in the URL. My Project is written primarily in PHP. This is a snippit of the code that makes the inital request for an authentication session.
function logOn($mainURL, $credentials)
{
// create a new HTTP_Request object to be used in the login process
$request = new HTTP_Request();
// set the URL of the HTTP_Request object to the family search identity/login endpoint
$request->setUrl("https://web-service/authentication/path?response_type=code&client_id=".$credentials['key']."&redirect_uri=https://www.myredirectPage.edu/");
$request->_useBrackets = false;
$request->addHeader("User-Agent", $credentials['agent']);
$request->addHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
$request->sendRequest();
//HTML_HEADER;
//the response will come in the form of an html file
$responseHtml = $request->getResponseBody();
//Dynamically load html from request body onto the browser to allow for authentication
echo $responseHtml;
return $credentials;
}
The end user will enter their login credentials using the loaded html components and hit submit. The web service then redirects to my redirect authentication page. The code there is provided below.
<?php
// process client request (Via url)
//gather code parameters from the redirect url.
if (isset($_GET['code']))
{
echo $_GET['code'];
}
else
{
echo "code not returned";
}
if (isset($_GET['error']))
{
echo $_GET['error'];
}
else
{
echo "error not returned";
}
?>
Thanks in advance to any help with this.
When I use Google Chrome's Network debugger tool, I saw that my project was making unexpected searches for Javascript and Css resources, all resulting in 404 (not found) errors. Upon closer inspection, I could see that the resources were relative paths to resources that are on the web service server. Rather than looking for 'https://webService.net/js/importantJavascript.js' (an existing file located on the service's web server), it was trying to find 'https://mywebpage.edu/js/importantJavascript.js'(a path to a file that doesn't exist).
I've been trying to implement openID authentication as a consumer in a project I'm developing, and I haven't yet managed to make even the examples work as I want.
Even though the example consumer works perfectly for yahoo openid authentication, it fails in the try_auth.php page with a 501 HTTP error when trying to use google openID.
Here's the code for try_auth.php (the page that handles the call to the actual openID provider):
<?php
error_reporting(E_ALL);
ini_set('display_errors','On');
require_once "common.php";
session_start();
function getOpenIDURL() {
// Render a default page if we got a submission without an openid
// value.
if (empty($_GET['openid_identifier'])) {
$error = "Expected an OpenID URL.";
include 'index.php';
exit(0);
}
return $_GET['openid_identifier'];
}
function run() {
$openid = getOpenIDURL();
$consumer = getConsumer();
// Begin the OpenID authentication process.
$auth_request = $consumer->begin($openid);
// No auth request means we can't begin OpenID.
if (!$auth_request) {
displayError("Authentication error; not a valid OpenID.");
}
$sreg_request = Auth_OpenID_SRegRequest::build(
// Required
array('nickname'),
// Optional
array('fullname', 'email'));
if ($sreg_request) {
$auth_request->addExtension($sreg_request);
}
$policy_uris = null;
if (isset($_GET['policies'])) {
$policy_uris = $_GET['policies'];
}
$pape_request = new Auth_OpenID_PAPE_Request($policy_uris);
if ($pape_request) {
$auth_request->addExtension($pape_request);
}
// Redirect the user to the OpenID server for authentication.
// Store the token for this authentication so we can verify the
// response.
// For OpenID 1, send a redirect. For OpenID 2, use a Javascript
// form to send a POST request to the server.
if ($auth_request->shouldSendRedirect()) {
$redirect_url = $auth_request->redirectURL(getTrustRoot(),
getReturnTo());
// If the redirect URL can't be built, display an error
// message.
if (Auth_OpenID::isFailure($redirect_url)) {
displayError("Could not redirect to server: " . $redirect_url->message);
} else {
// Send redirect.
header("Location: ".$redirect_url);
}
} else {
// Generate form markup and render it.
$form_id = 'openid_message';
$form_html = $auth_request->htmlMarkup(getTrustRoot(), getReturnTo(),
false, array('id' => $form_id));
// Display an error if the form markup couldn't be generated;
// otherwise, render the HTML.
if (Auth_OpenID::isFailure($form_html)) {
displayError("Could not redirect to server: " . $form_html->message);
} else {
print $form_html;
}
}
}
run();
?>
Another think I noticed is that on my windows dev box (Apache 2.2.6 standalone, not XAMPP, PHP 5.3.8) everything runs smoothly, both yahoo and Google perform openID authentication without any issues.
Anyone have an idea what might be wrong?
Thanks in advance.
After some trial and error, I came to the conclusion that the 501 error occurs due to the Google openID url being passed to the page either as querystring (for form method "get") either as postdata (for form method "post"). In particular, the url I was using is
https://www.google.com/accounts/o8/id
the last part (the "id") is triggering the 501 error. If I use
https://www.google.com/accounts/o8/id/
the error is not triggered. Well, since the two are equivalent urls, I'll be using the second one. I'm still curious as to why this was happening though.