How-tos

Protect your PHP app with Mobile Client Access

Share this post:

Overview

Mobile Client Access (MCA) allows you to protect any web application with social identity providers like Facebook and Google. It also allows you to create your own custom identity provider. In this blog post, we’ll cover how to instrument our PHP application for authentication.

Create a new Mobile Client Instance

Begin by choosing an existing Mobile Client Access instance or create a new one. Then, configure the identity provider (i.e., Facebook, Google, or custom). In this example, we’ll use Facebook, which requires you to have a Facebook Developers account. To configure the Facebook identity provider for web in Mobile Client Access, you’ll need your Facebook App ID and App Secret; you’ll also need the redirect URL where Mobile Client Access will redirect your user after authorization.

Instrumenting your application

For this blog I’ll be using an application built using Slim, a micro framework for PHP. Slim is compliant with the PSR7 specification, therefore the code below applies to any framework compatible with PSR7. We’ll also be using Guzzle HTTP Client, and Zend Diactoros.

Dependency management is handled by Composer so we’ll add our dependencies in the composer.json file.

<code>{
"require": {
"zendframework/zend-diactoros": "^1.3",
"slim/slim": "^3.5",
"guzzlehttp/guzzle": "^6.2"
}
}
</code>

Alternatively, we can add our dependencies via the composer cli i.e., composer require guzzlehttp/guzzle:~6.0

Our application has a protected endpoint that can only be accessed if the user has already authenticated through Mobile Client Access. The protected endpoint will be monitored by a middleware that checks for a valid user session. If the session is active, then we let the user proceed; otherwise we send the user to the login page.

<code>$app-&gt;group('/protected', function () use ($app) {
$app-&gt;get('/profile', function (Request $request, Response $response) {
// this endpoint is only reached with a valid user session
});

$app-&gt;get('/settings', function (Request $request, Response $response) {
// this endpoint is only reached with a valid user session
});
})-&gt;add('protectedMiddleware');

function protectedMiddleware(Request $request, Response $response, $next){
/** @var SessionManager $session */
$session = $request-&gt;getAttribute('session');
if(!$session-&gt;get('userIdentity')) {
return new RedirectResponse('/auth/login');
}

return null === $next ? $response : $next($request, $response);
}
</code>


For the login, we’re sending the user to authenticate with Mobile Client Access. In this case we’ve configured Mobile Client Access to use Facebook as the identity provider, so the user will be redirected to Facebook to accept the login request. If accepted, Facebook will redirect the user back to Mobile Client Access and then it will redirect the user back to the callback endpoint (specified before) with a grant code that we’ll use to obtain an access token.

The code below shows three endpoints /auth/logout, /auth/login, and /auth/callback. /auth/logout simply clears the user session, /auth/login redirects the user to Mobile Client Access, and /auth/callback obtains the grant token to then request access and identity tokens.

<code>$app-&gt;group('/auth', function () use ($app, $credentials) {
$app-&gt;get('/logout', function (Request $request, Response $response) {
/** @var SessionManager $session */
$session = $request-&gt;getAttribute('session');
$session-&gt;destroy();
return new RedirectResponse('/');
});
$app-&gt;get('/login', function (Request $request, Response $response) use ($credentials) {
$params = array(
'response_type' =&gt; 'code',
'client_id' =&gt; $credentials['clientId'],
'redirect_uri' =&gt; 'http://' . $request-&gt;getUri()-&gt;getHost() . '/auth/callback'
);

return new RedirectResponse($credentials['authorizationEndpoint'] . '?' . http_build_query($params));
});

$app-&gt;get('/callback', function (Request $request, Response $response) use ($credentials) {
$params = $request-&gt;getQueryParams();
if (isset($params['code']) &amp;&amp; $code = $params['code']) {
try {
/** @var SessionManager $session */
$session = $request-&gt;getAttribute('session');
$client = new Client();
$response = $client-&gt;post($this-&gt;credentials['tokenEndpoint'], [
'headers' =&gt; [
'Authorization' =&gt; 'Basic ' . \base64_encode($this-&gt;credentials['tenantId'] . ':' . $this-&gt;credentials['secret'])
],
'form_params' =&gt; [
'grant_type' =&gt; 'authorization_code',
'client_id' =&gt; $this-&gt;credentials['clientId'],
'redirect_uri' =&gt; 'http://' . $request-&gt;getUri()-&gt;getHost() . '/auth/callback',
'code' =&gt; $code
]
]);
$body = \json_decode($response-&gt;getBody()-&gt;getContents(), true);
$session-&gt;set('accessToken', $body['access_token']);
$session-&gt;set('idToken', $body['id_token']);
list($header, $payload, $signature) = explode('.', $body['id_token']);
$identity = \json_decode(base64_decode($payload), true);
$session-&gt;set('userIdentity', $identity['imf.user']);
return new RedirectResponse('/');
} catch (RequestException $e) {
if ($e-&gt;hasResponse()) {
return $e-&gt;getResponse()-&gt;getBody()-&gt;getContents();
}
return 'Error: ';
}
}
return new RedirectResponse('/');
});
});
</code>


Once you’ve obtained the access and identity tokens, you can initialize the session so that the user has access to the protected resources. The access and identity tokens are base64 encoded based on the JWT standard. The identity token contains information about the user such as name, age, picture, etc.

Final Thoughts

In this blog we instrumented our PHP application to use Mobile Client Access to protect an endpoint. Mobile Client Access can be used to protect any type of web application including PHP, NodeJS, Java, Python, Ruby, etc.

More How-tos stories
April 5, 2019

IBM Cloud App ID: Updated Runtime APIs Provide Tighter Interoperability for Your Cloud-Native Apps

As part of our efforts to tighten interoperability and broaden the frameworks that are able to use IBM Cloud App ID, we've updated the runtime APIs.

Continue reading

February 11, 2019

IBM Cloud Mobile Foundation: Top-10 Features to Boost Your App Rating

The Mobile Foundation service offers many hidden gems that developers often gloss over. In this post, we highlight the top 10 features that increase user engagement as well as improve app ratings. 

Continue reading

February 8, 2019

Distribute CoreML Models Securely Using Mobile Foundation Service

IBM Mobile Foundation is excited to introduce a feature to manage the distribution of CoreML models.

Continue reading