Category Archives: OAuth

As you probably know, eCommerce portal with OAuth2 development can be broken up into three main areas:

  • Setup eCommerce portal using OpenCart
  • Installing vQmod extension for OpenCart
  • Add REST API with OAuth2.0 to OpenCart

Setup eCommerce portal using OpenCart

Setup eCommerce portal using OpenCart. Here is a link for reference.

Installing vQmod extension for OpenCart

“vQmod” (aka Virtual Quick Mod) is an override system designed to avoid having to change OpenCart core files.

How to install vQmod using Autoinstaller

1) Download the latest version that has “opencart” in the title from the download area.

  1. Using FTP, upload the “vqmod” folder from the zip to the root of your opencart store.
  2. Be sure the vqmod folder and the vqmod/vqcache folders are writable (either 755 or 777).
    • Also be sure index.php and admin/index.php are writable.
      • If you’re not sure, then try 755.
      • If you get errors about permissions, then try 777.

NOTE: 777 permissions are dangerous and should only be used as a last resort. If your hosting requires this, consult your hosting to let them know this shouldn’t be necessary

  1. Goto http://www.yoursite.com/vqmod/install
  2. You should get a success message. If not, check the above permissions, and try again
  3. Load your store homepage and verify that it works.
  4. Using FTP, verify that there are new “vq” files in the “vqmod/vqcache” folder.
  5. If yes, then you are ready to start downloading or creating vQmod scripts, otherwise ask for assistance.

Done!

  • DO NOT DELETE THE INSTALL FOLDER!
  • YOU MUST RUN THE INSTALLER EVERY TIME YOU UPGRADE OPENCART!!
  • THERE IS NO DANGER OF RE-RUNNING THE INSTALLER!

How to install vQmod manually?

1) Download the latest version that has “OpenCart” in the title.

  1. Using FTP, upload the “vqmod” folder from the zip to the root of your OpenCart store.
  2. Be sure the vqmod folder and the vqmod/vqcache folders are writable (either 755 or 777).
    • Also be sure index.php and admin/index.php are writable.
      • If not sure which you need, first try 755.
      • If you get errors about permissions, then try 777.
  3. Edit your index.php file.
  4. FIND

  5. REPLACE WITH

Note the affiliate library file may not exist on older systems. Basically any require_once(DIR_SYSTEM . 'library/xxxxxxxx.php'); needs to be changed to use the VQMod::modCheck above in the same format. This also applies to any additional require_once files in the next step

  1. Edit your admin/index.php file
  2. FIND

  3. REPLACE WITH

  4. Load your store homepage and verify if it works.
  5. Using FTP, verify that there are new “vq” files in the “vqmod/vqcache” folder.
  6. If yes, then you are ready to start downloading or creating vQmod scripts.

Done!

Add REST API with OAuth2.0 to OpenCart

OpenCart Rest API is a full featured API that allows you to set up your own rest services within minutes.

You can download it here.
The upload folder contains all files for this module.
You will notice that the folders are in the same structure as your OpenCart installation.

1. Navigate to your opencart root folder using an FTP program.
2. Upload all folders of extension to your opencart installation folder.
3. Execute these SQL statements in phpMyAdmin or whatever client you use for managing your database.

4. Go to your admin area in Extensions->Modules and enable your REST API extension.
You have to fill the Order id field (you can find it in the order email)
You have to fill the client id, client secret fields and TTL. This is needed for authentication with the API.

5. Paste into your opencart root folder .htaccess file after “RewriteRule ^([^?]*) index.php?_route_=$1 [L,QSA]”
RewriteRule .* – [E=HTTP_Authorization:%{HTTP:Authorization}]

6. Paste into your opencart root folder .htaccess file after “RewriteBase /”

Now we’re able to run Mobile Apps using our own E-Commerce website REST and OAuth2.0 API.

The intent is to implement OAuth2 provider protocol & secure appropriate rest api’s using OAuth2 token.

The generic need for any application would be to have some public API’s that can be accessed without any security, & some secured using token associated with clientId/secretKey & some secured using token associated with user credentials.

The following are the rest endpoints supporting OAuth2, which provide a token using different protocols, i.e Authorization Code Grant flow (1a,1b), Implicit Grant flow (2), Resource Owner Password Grant (3), Client Credentials Grant (4), Refresh Token Grant(5).

  • OAuth2 Rest End Points 
      1. [ GET] /oauth/authorize:
        • (1a) OAuth2 Authorization Code Grant
          parameters [ ?response_type=code&client_id=my-client&scope=read ]
        • (2) OAuth2 Implicit Grant
          parameters [ ?response_type=token&client_id=my-client&scope=read ]
      2. [ POST] /oauth/token:
            • (1b) OAuth2 Authorization Code Grant
              parameters [ ?grant_type=authorization_code&code=139R59&client_id=my-client ]
            • (3) OAuth2 Resource Owner Password Grant.
              parameters [ ?grant_type=password&client_id=..&client_secret=my-secret&username=aa&password=bb&scope=read ]
            • (4) OAuth2 Client Credentials Grant
              parameters [ ?grant_type=client_credentials&client_id=my-client&scope=read ]
            • (5) OAuth2 Refresh Token Grant
              parameters [ ?grant_type=refresh_token&refresh_token=22c3f395-690c-4838-a14f-3137e6802db1&client_id=my-client&scope=read ]

The following are the API endpoints we would like to support using the token provided above

    1. Public API’s
      1. [  GET] /api/v0/about
      2. [  GET] /api/v0/sample/about
    2. Secured access using a Client Token
      1. [  GET] /api/v0/sample/securedWithClientOAuth : Sample API secured with client token
      2. [POST] /api/v0/members/signup: Create a new User
      3. [POST] /api/v0/auth/login: Login using username/password credentials
    3. Secured access using User Token
      1. [  GET] /api/v0/sample/securedWithUserOAuth: Sample Secured with user token
      2. [  GET] /api/v0/members: Get list of members supports pagination ?filter=”field1=value,field2=v”&sort=”field2″&offset=15
      3. [  GET] /api/v0/members/{memberId}: Get information about a user
      4. [  PUT] /api/v0/members/{memberId}: update a user
      5. [  GET] /api/v0/auth/logout: logout the user associated with the token

In addition, we would want the api server to respond with the following standard HTTP Status responses across all api calls

  1. HTTP 200: Any successful REST api call along with its specific json data
  2. HTTP 400: Any api that results in validation errors like “invalid username”, “empty password” etc. along with json data with list of property errors
    “{ [propertyName:””, messageCode:””, message:””], [propertyName:””,messageCode:””].. }
  3. HTTP 404: Any non-existent REST api request using json along with json response of
    { messageCode:”api.notfound”, message:”locale based message desc”}
  4. HTTP 500: Any REST api request resulting in internal error along with json response of
    {messageCode:”api.internal.error”, message:”locale based message” }
  5. HTTP 403: Any REST api request resulting in forbidden
  6. HTTP 405: Any REST api request using invalid method i.e using GET instead of POST/PUT

Any REST API that supports pagination should respond data in the following format, with results containing the appropriate list items and accept “filter”,”offset”,”sort” & “order” as parameters.

{ 
      "from":10, 
        "to":15, 
"totalCount":100,
     results: [
       { prop1:"", prop2:"" },
       { prop1:"", prop2:"" },
       { prop1:"", prop2:"" },
       { prop1:"", prop2:"" },
       { prop1:"", prop2:"" }
     ]
}

Here is sample input/output for the api endpoints for successful responses

Input Output
[POST] /api/v0/members/signup: Create a new User
curl –X POST –d ‘{
“clientId”:”my-client”,
“username”:”abcdef”,
“password”:”123456″,
“email”:”abcd@ef.com”,
“firstName”:”abcd”
}’
{“member”: {
“description”: “”,
“email”: “abcd@ef.com”,
“firstName”: “abcd”,
“id”: 5,
“lastName”: “”,
“phone”: 0,
“socialAccounts”: []
},
“token”: {
“access_token”: “7224..”,
“expires_in”: 43199,
“refresh_token”: “ebff..”,
“scope”: “read,write”,
“token_type”: “bearer”
} }
[POST] /api/v0/auth/login: Member Login
curl –X POST –d ‘{
“clientId”: “my-client”,
“username”: “abcdef”,
“password”: “123456”
}’
{“member”: {
“description”: “”,
“email”: “abcd@ef.com”,
“firstName”: “abcd”,
“id”: 5,
“lastName”: “”,
“phone”: 0,
“socialAccounts”: []
},
“token”: {
“access_token”: “7224..”,
“expires_in”: 43199,
“refresh_token”: “ebff..”,
“scope”: “read,write”,
“token_type”: “bearer”
} }
[  GET] /api/v0/members/{memberId}: Get Member
curl -H     “Authorization: Bearer 7224…” http://../api/v0/members/5 {
“description”: “”,
“email”: “abcd@ef.com”,
“firstName”: “abcd”,
“id”: 5,
“lastName”: “”,
“phone”: 0,
“socialAccounts”: []
}
[  PUT] /api/v0/members/{memberId}: Update Member
curl –X PUT –H “Authorization: Bearer 7224…”
-d { “id”: 5, “firstName”: “fname”, “lastName”: “lname”,”phone”: 0, “description”: “desc”} http://../api/v0/members/5
{
“description”: “desc”,
“email”: “abcd@ef.com”,
“firstName”: “fname”,
“id”: 5,
“lastName”: “lname”,
“phone”: 0,
“socialAccounts”: []
}


We will walk thru the implementation in the following sequence.

      1. Implement OAuth2 endpoints using OAuth2 Server library along with sample endpoints access controlled by client/user tokens
      2. Annotate your API with Swagger-UI
      3. Create API for Member Create/Read/Update
      4. Write Unit tests for Member Create/Read/Update
      5. Create API for Auth login/logout & Write Unit Tests

1. Create API for Member Create/Read/Update

Lets make a list of features that we want, just so it would guide us in our design.

  Feature
Login Domain
1a Ensure that password is getting encrypted while saving
1b We shouldn’t be able to create new Login with same username
1c We should have the ability to expire an account
1d We should have the ability to lock an account
Member Domain
2a Each member should have a unique UUID to identify them using URL
2b We cannot have two members with same email
2c A Member cannot exist without a Login
API / MemberController / create
3a Registration with an existing username should respond with 400
3b Registration with an existing email should respond with 400
3c Invalid email syntax should return 400
3d Successful registration should respond with 200 along with member info

Given the list of features, we will start off with the following ER Model

login-member-ermodel

If you are looking for PHP implementation, here is the link

If you are looking for Grails implementation, here is the link

In this post, we’ll learn how to deploy and use REST OAuth2.0 API server using PHP.
Here, REST API using OAuth2

The generic need for any application would be to have some public API’s that can be accessed without any security, & some secured using token associated with clientId/secretKey & some secured using token associated with user credentials.

We will walk thru the implementation in the following sequence.

      1. Implement OAuth2 endpoints using PHP OAuth2 Server library along with sample endpoints access controlled by client/user tokens
      2. Annotate your API with Swagger-UI
      3. Create API for Member Create/Read/Update
      4. Write Unit tests for Member Create/Read/Update
      5. Create API for Auth login/logout & Write Unit Tests

Before we start ensure that your environment is all set

      • Install XAMPP
      • Create a starter app using starter-app-php

        Create a schema named starter_app_dev in mysql using phpMyAdmin.
        Copy code into starter-app-php folder
        Now ready http://localhost/starter-app-php/ app

1 viagra est il en vente libre. Create API for Member Create/Read/Update

Lets make a list of features that we want, just so it would guide us in our design.

  Feature
Login Domain
1a Ensure that password is getting encrypted while saving
1b We shouldn’t be able to create new Login with same username
1c We should have the ability to expire an account
1d We should have the ability to lock an account
Member Domain
2a Each member should have a unique UUID to identify them using URL
2b We cannot have two members with same email
2c A Member cannot exist without a Login
API / MemberController / create
3a Registration with an existing username should respond with 400
3b Registration with an existing email should respond with 400
3c Invalid email syntax should return 400
3d Successful registration should respond with 200 along with member info

Given the list of features, we will start off with the following ER Model

login-member-ermodel

Our next step is to create a module classes in CI.

class MemberModel extends CI_Model
{

    function __construct()
    {
        parent::__construct();
    }

    function addLogin($pdata)
    {
        $this->db->insert("login", $pdata);
        return $this->db->insert_id();
    }

    function addMember($pdata)
    {
        $this->db->insert("member", $pdata);
        return $this->db->insert_id();
    }

    function updateMemberById($id, $pdata)
    {
        $this->db->where("id", $id);
        return $this->db->update("member", $pdata);
    }

    function updateMemberByLoginId($login_id, $pdata)
    {
        $this->db->where("login_id", $login_id);
        return $this->db->update("member", $pdata);
    }

    function getLoginByUsername($username)
    {
        $this->db->select("m.*");
        $this->db->where("m.username", $username);
        $query = $this->db->get("login m");
        if ($query->num_rows() > 0) {
            return $query->row_array();
        }
        return false;
    }

    function getMemberById($login_id)
    {
        $this->db->select("u.*");
        $this->db->where("m.id", $login_id);
        $this->db->join("member u", "m.id=u.login_id");
        $query = $this->db->get("login m");
        if ($query->num_rows() > 0) {
            return $query->row_array();
        }
        return false;
    }

    function getMemberByLoginId($login_id)
    {
        $this->db->select("u.*");
        $this->db->where("m.id", $login_id);
        $this->db->join("member u", "m.id=u.login_id");
        $query = $this->db->get("login m");
        if ($query->num_rows() > 0) {
            $row = $query->row_array();            
            return $row;
        }
        return false;
    }

    function checkUsername($username)
    {
        $this->db->select("m.*");
        $this->db->where("m.username", $username);
        $query = $this->db->get("login m");
        if ($query->num_rows() > 0) {
            return true;
        }
        return false;
    }

}

Lets Create our first API to create a Member
Add an action to create Member.

include_once(APPPATH . "libraries/OAuth2/Autoloader.php");

class Member extends BaseApi
{
    function __construct()
    {
        // Construct the parent class
        parent::__construct();
        $this->load->library('oauth');
        $this->load->model("MemberModel", "memberModel");
    }

    function create_post()
    {
        $this->server = $this->oauth->getOauthServer();
        $request = OAuth2\Request::createFromGlobals();
        $request->request['response_type'] = "token";
        if (empty($request->request['state'])) {
            $request->request['state'] = "create";
        }
        $response = new OAuth2\Response();

        if (!$this->server->validateAuthorizeRequest($request, $response)) {
            $this->set_response_error($response->getParameters());
        } else {
            $errors = [];
            if (!empty($this->post('username')) && $this->apiModel->checkUsername($this->post('username')) === true) {
                $errors[] = [
                    "messageCode" => "user.username.exists",
                    "message" => "user.username.exists",
                    "objectName" => "",
                    "propertyName" => "username"
                ];
            } else if (empty($this->post('username'))) {
                $errors[] = [
                    "messageCode" => "user.username.invalid",
                    "message" => "user.username.invalid",
                    "objectName" => "",
                    "propertyName" => "username"
                ];
            }
            if (empty($this->post('password'))) {
                $errors[] = [
                    "messageCode" => "user.password.invalid",
                    "message" => "user.password.invalid",
                    "objectName" => "",
                    "propertyName" => "password"
                ];
            }
            if (empty($this->post('firstName'))) {
                $errors[] = [
                    "messageCode" => "user.firstName.invalid",
                    "message" => "user.firstName.invalid",
                    "objectName" => "",
                    "propertyName" => "firstName"
                ];
            }

            if (empty($errors)) {
                $login_data = array();
                $login_data['username'] = $this->post('username');
                $login_data['password'] = $this->post('password');
                $login_data['password_expired'] = 0;
                $login_data['account_expired'] = 0;
                $login_data['account_locked'] = 0;
                $login_data['enabled'] = 1;
                $login_id = $this->apiModel->addLogin($login_data);
                if ($login_id !== false) {
                    $member_data = array();
                    $member_data['login_id'] = $login_id;
                    $member_data['first_name'] = ($this->post("firstName") !== null) ? $this->post("firstName") : "";
                    $member_data['last_name'] = ($this->post("lastName") !== null) ? $this->post("lastName") : "";
                    $member_data['email'] = ($this->post("email") !== null) ? $this->post("email") : "";
                    $member_data['phone'] = ($this->post("phone") !== null) ? $this->post("phone") : "";
                    $member_data['description'] = ($this->post("description") !== null) ? $this->post("description") : "";
                    $member_id = $this->apiModel->addMember($member_data);
                }
            }

            if (empty($errors)) {
                $member = $this->apiModel->getMemberByLoginId($login_id);
                $this->server = $this->oauth->getOauthServer(["password"]);
                $request = OAuth2\Request::createFromGlobals();
                $request->request['grant_type'] = "password";
                $token = $this->server->handleTokenRequest($request)->getParameters();

                $this->set_response_success([
                    "member" => $member,
                    "token" => $token
                ]);
            } else {
                $this->set_response_error([
                    "errors" => $errors
                ]);
            }
        }
    }

    function login_post()
    {
        $this->server = $this->oauth->getOauthServer(["password", "refresh_token"]);
        $request = OAuth2\Request::createFromGlobals();
        $request->request['grant_type'] = "password";
        $token = $this->server->handleTokenRequest($request)->getParameters();
        $member_data = [];
        if(!empty($token['user_id'])){
            $member_data = $this->apiModel->getMemberByLoginId($token['user_id']);
        }
        if (!empty($token['access_token'])) {
            $this->set_response_success([
                "member" => $member_data,
                "token" => $token
            ]);
        } else {
            $this->set_response_error($token);
        }
    }
    
}

 

We will continue this post with creating tests for the features that we have built.

What is OAuth

OAuth is an open standard for authorization, commonly used as a way for Internet users to log into third party websites using their Microsoft, Google, Facebook or Twitter accounts without exposing their password.

Generally, OAuth provides to clients(eg. Mobile app) a ‘secure delegated access’ to server resources on behalf of a resource owner.

If you are implementing OAuth as server, where your clients are suppose to use your resources. Then we have to understand OAuth 2.0 Grant types.

WEB APPLICATIONS using Authorization Code Grant Type.

The Web-server applications scenario is used to authenticate a web application with a third-party service (e.g., imagine you built a web application that needs to consume the API of Facebook). You can authenticate your application using the third-party server with a 3-step flow
first

When using a three-legged OAuth server, the typical flow that a developer would take to implement and consume the service is as follows.

second

The above image, courtesy of Google Oauth Playground, in simple terms it shows following.

  1. Consumer request’s for a token.
  2. In Response consumer will receive authorization code from Server.
  3. Consumer exchanges the Auth code for token.
  4. Server responds with Oauth token.
  5. Once The OAuth token is retrieved, and developer can now make secure requests by passing the token for validation.
  6. Token can passed as Authorization http header in every request as “Bearer <token> ”.

 

Browser based Applications (Single Page Application) using Implict GrantType

This scenario is quite common when using a Javascript client (e.g., a Single Page Application) that requests access to the API of a third-party server. In a browser-based application, you cannot store the client_secret in a secure way, which means you cannot use the previous workflow (web-server application). Instead, we need to use an implicit grant. This is similar to the authorization code, but rather than an authorization code being returned from the authorization request, a token is returned.

In the following diagram, we illustrate the 2 steps needed for the authentication of browser-based application scenarios:

third

Mobile App implementation:

This OAuth2 scenario is similar to browser-based applications. The only difference is the redirect_uri, which, in the mobile world, can be a custom URI scheme. This allow native mobile apps to interact with a web browser application, opening a URL from a native app and going back to the app with a custom URI. For example, iPhone apps can register a custom URI protocol such as facebook://. On Android, apps can register URL matching patterns which will launch the native app if a URL matching the pattern is visited. Below illustrates OAuth2 authentication with Mobile apps:

fourth

Mobile APP with username and password access using Password GrantType:

This use case can be used to authenticate an API with user based grants (also known as a password grant). The typical scenario includes a Login web page with username and password that is used to authenticate against a first-party API. Password grant is only appropriate for trusted clients. If you build your own website as a client of your API, then this is a great way to handle logging in.

The authentication mechanism is just 1 step (see diagram below).
sixth

Confidential Client Scenarios

With confidential, trusted clients, you provide the client_id and client_secret as HTTP Basic authentication credentials, and the username, and password values in the request body, in order to obtain an access token.
This is used quite often in mobile apps.

seventh

By implementing any one of those grantype, we can get access token to access resources. But this access token has an expiry time. So how do we get new token.

Generate Refresh Token using RefreshToken GrantType

The OAuth2 protocol gives you the possibility to refresh the access token, generating a new one with a new lifetime. This action can be performed using the refresh_token that the OAuth2 server provides in the response during the authentication step.

eight

Access to protected Resource.
Once the client or user-agent (in the implicit grant flow) has the access token, it has to use it to access the protected resource. There are 2 standard ways of sending the access token in every request.

Every request should have this Authorization header for protected resources.

  • BEARER TOKEN
    The access token is should be placed in the Authorization HTTP header, and may only be placed in a POST request body, or the GET URL parameters as a fallback option.
    Eg : Authorization : Bearer <access_token_received>
  • MAC
    A cryptographic MAC (Message Authentication Code) is computed using elements of the request and sent in the Authorization header. The Resource Owner computes and compares the MAC upon receiving the request. The access token may only be placed in the Authorization HTTP header
    Under MAC token profile, this is how it looks like.

    Authorization: MAC id=”h480djs93hd8″, ts=”1336363200″, nonce=”dj83hs9s”, mac=”bhCQXTVyfj5cmA9uKkPFx1zeOXM=”

    This needs bit more attention.

    id is the MAC key identifier or the access_token.

    ts the request timestamp. The value is a positive integer set by the client
    when making each request to the number of seconds elapsed from a fixed point in time (e.g. January 1, 1970 00:00:00 GMT). This value is unique across all requests with the same timestamp and MAC key identifier combination.

    nonce is a unique string generated by the client. The value is unique across all requests with the same timestamp and MAC key identifier combination.

    The client uses the MAC algorithm and the MAC key to calculate the request mac.

Either you use Bearer or MAC – the end user or the resource owner is identified using the access_token. Authorization, throttling, monitoring or any other quality of service operations can be carried out against the access_token irrespective of which token profile you use.