Login with GitHub OAuth API using PHP

GitHub provides a web-based hosting service for version control. It plays an important role in software and web development. Presently GitHub has over 28 million users from around the world. If you want to allow users to log in with their social account, GitHub can be the best option besides the other social media OAuth Login (Facebook OAuth API, Google OAuth API, Twitter OAuth API, etc.). GitHub OAuth Login is a quick and powerful way to integrate user login system into the web application.

GitHub authentication API allows the users to sign in to the website using their GitHub account without registration on your website. Login with GitHub account can be easily implemented using GitHub OAuth API. In this tutorial, we will show you how to integrate the user login and registration system with GitHub using PHP and store the user’s profile data in the MySQL database.

Before getting started, take a look at the file structure to implement GitHub Login with PHP.

github_login_with_php/
├── config.php
├── index.php
├── logout.php
├── User.class.php
├── src/
│   └──Github_OAuth_Client.php
├── css/
│   └── style.css
└── images/
    └── github-login.png

Create GitHub OAuth Application

You need to create and register OAuth App to access GitHub API. Also, the Client ID and Client Secret need to be specified at the time of the GitHub API call. Follow the below steps to create and configure the GitHub OAuth application.

  • Log in to your GitHub account. In the upper-right corner, click your profile picture and then click Settings.
    github-login-oauth-app-account-settings-codexworld
  • In the settings page, click Developer settings on the left sidebar.
    github-login-oauth-app-developer-settings-codexworld
  • In the left sidebar, click OAuth Apps. To create new OAuth app, click the Register a new application.
    github-login-oauth-register-new-application-codexworld
  • Enter all the necessary information (Application name, Homepage URL, Application description, and Authorization callback URL) to register your new OAuth application. Click Register application when you’re done.
    github-login-create-oauth-api-application-codexworld
  • Client ID and Client Secret of the application will be generated. Copy the GitHub OAuth details (Client ID and Client Secret) for later use in the script to access GitHub API.
    github-login-oauth-app-api-client-id-secret-codexworld

Create Database Table

To store the user’s profile information from the GitHub account, a table needs to be created in the database. The following SQL creates a users table with some basic fields in the MySQL database.

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `oauth_provider` enum('github','facebook','google','twitter') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'github',
  `oauth_uid` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `username` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `location` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `picture` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `link` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `created` datetime NOT NULL DEFAULT current_timestamp(),
  `modified` datetime NOT NULL DEFAULT current_timestamp(),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Github OAuth Client for PHP (Github_OAuth_Client.php)

The Github_OAuth_Client class is a custom PHP library that handles GitHub REST API calls for OAuth-related requests.

  • getAuthorizeURL() – Generate URL to authorize with the Github account.
  • getAccessToken() – Exchange oauth code and get access token from Github OAuth API.
  • apiRequest() – Make an API call and retrieve the access token from Github OAuth API.
  • getAuthenticatedUser() – Execute the cURL request to get the authenticated user account data from Github User API.
<?php 
/*
 * Class Github_OAuth_Client
 * 
 * Author: CodexWorld
 * Author URL: https://www.codexworld.com
 * Author Email: admin@codexworld.com
 * 
 * The first PHP Library to support OAuth for GitHub REST API.
 */
class Github_OAuth_Client{
    public 
$authorizeURL "https://github.com/login/oauth/authorize";
    public 
$tokenURL "https://github.com/login/oauth/access_token";
    public 
$apiURLBase "https://api.github.com";
    public 
$clientID;
    public 
$clientSecret;
    public 
$redirectUri;
    
    
/**
     * Construct object
     */
    
public function __construct(array $config = []){
        
$this->clientID = isset($config['client_id']) ? $config['client_id'] : '';
        if(!
$this->clientID){
            die(
'Required "client_id" key not supplied in config');
        }
        
        
$this->clientSecret = isset($config['client_secret']) ? $config['client_secret'] : '';
        if(!
$this->clientSecret){
            die(
'Required "client_secret" key not supplied in config');
        }
        
        
$this->redirectUri = isset($config['redirect_uri']) ? $config['redirect_uri'] : '';
    }
    
    
/**
     * Get the authorize URL
     *
     * @returns a string
     */
    
public function getAuthorizeURL($state){
        return 
$this->authorizeURL '?' http_build_query([
            
'client_id' => $this->clientID,
            
'redirect_uri' => $this->redirectUri,
            
'state' => $state,
            
'scope' => 'user:email'
        
]);
    }
    
    
/**
     * Exchange token and code for an access token
     */
    
public function getAccessToken($state$oauth_code){
        
$token self::apiRequest($this->tokenURL '?' http_build_query([
            
'client_id' => $this->clientID,
            
'client_secret' => $this->clientSecret,
            
'state' => $state,
            
'code' => $oauth_code
        
]));
        return 
$token->access_token;
    }
    
    
/**
     * Make an API request
     *
     * @return API results
     */
    
public function apiRequest($access_token_url){
        
$apiURL filter_var($access_token_urlFILTER_VALIDATE_URL)?$access_token_url:$this->apiURLBase.'user?access_token='.$access_token_url;
        
$context  stream_context_create([
          
'http' => [
            
'user_agent' => 'CodexWorld GitHub OAuth Login',
            
'header' => 'Accept: application/json'
          
]
        ]);
        
$response file_get_contents($apiURLfalse$context);
        
        return 
$response json_decode($response) : $response;
    }

    
/**
     * Get the authenticated user
     *
     * @returns object
     */
    
public function getAuthenticatedUser($access_token) {
        
$apiURL $this->apiURLBase '/user';
        
        
$ch curl_init();
        
curl_setopt($chCURLOPT_URL$apiURL);
        
curl_setopt($chCURLOPT_RETURNTRANSFER1);
        
curl_setopt($chCURLOPT_SSL_VERIFYPEERFALSE); 
        
curl_setopt($chCURLOPT_HTTPHEADER, array('Content-Type: application/json''Authorization: token '$access_token));
        
curl_setopt($chCURLOPT_USERAGENT'CodexWorld GitHub OAuth Login');
        
curl_setopt($chCURLOPT_CUSTOMREQUEST'GET');
        
$api_response curl_exec($ch);
        
$http_code curl_getinfo($chCURLINFO_HTTP_CODE);         
         
        if(
$http_code != 200){
            if (
curl_errno($ch)) { 
                
$error_msg curl_error($ch); 
            }else{
                
$error_msg $api_response;
            }
            throw new 
Exception('Error '.$http_code.': '.$error_msg);
        }else{
            return 
json_decode($api_response);
        }
    }
}

User Class (User.class.php)

The User class handles the database related operations (fetch, insert, and update). Specify the database host ($dbHost), username ($dbUsername), password ($dbPassword), and name ($dbName) as per your MySQL database credentials.

  • __construct() – Connect to the database.
  • checkUser() – Check whether the user data already exists in the database. Update if user data exists, otherwise insert user’s profile data in the users table using PHP and MySQL.
<?php 
/*
 * User Class
 * This class is used for database related (connect, insert, and update) operations
 * @author    CodexWorld.com
 * @url        http://www.codexworld.com
 * @license    http://www.codexworld.com/license
 */

class User {
    private 
$dbHost     DB_HOST;
    private 
$dbUsername DB_USERNAME;
    private 
$dbPassword DB_PASSWORD;
    private 
$dbName     DB_NAME;
    private 
$userTbl    DB_USER_TBL;
    
    function 
__construct(){
        if(!isset(
$this->db)){
            
// Connect to the database
            
$conn = new mysqli($this->dbHost$this->dbUsername$this->dbPassword$this->dbName);
            if(
$conn->connect_error){
                die(
"Failed to connect with MySQL: " $conn->connect_error);
            }else{
                
$this->db $conn;
            }
        }
    }
    
    function 
checkUser($data = array()){
        if(!empty(
$data)){
            
// Check whether the user already exists in the database
            
$checkQuery "SELECT * FROM ".$this->userTbl." WHERE oauth_provider = '".$data['oauth_provider']."' AND oauth_uid = '".$data['oauth_uid']."'";
            
$checkResult $this->db->query($checkQuery);
            
            
// Add modified time to the data array
            
if(!array_key_exists('modified',$data)){
                
$data['modified'] = date("Y-m-d H:i:s");
            }
            
            if(
$checkResult->num_rows 0){
                
// Prepare column and value format
                
$colvalSet '';
                
$i 0;
                foreach(
$data as $key=>$val){
                    
$pre = ($i 0)?', ':'';
                    
$colvalSet .= $pre.$key."='".$this->db->real_escape_string($val)."'";
                    
$i++;
                }
                
$whereSql " WHERE oauth_provider = '".$data['oauth_provider']."' AND oauth_uid = '".$data['oauth_uid']."'";
                
                
// Update user data in the database
                
$query "UPDATE ".$this->userTbl." SET ".$colvalSet.$whereSql;
                
$update $this->db->query($query);
            }else{
                
// Add created time to the data array
                
if(!array_key_exists('created',$data)){
                    
$data['created'] = date("Y-m-d H:i:s");
                }
                
                
// Prepare column and value format
                
$columns $values '';
                
$i 0;
                foreach(
$data as $key=>$val){
                    
$pre = ($i 0)?', ':'';
                    
$columns .= $pre.$key;
                    
$values  .= $pre."'".$this->db->real_escape_string($val)."'";
                    
$i++;
                }
                
                
// Insert user data in the database
                
$query "INSERT INTO ".$this->userTbl." (".$columns.") VALUES (".$values.")";
                
$insert $this->db->query($query);
            }
            
            
// Get user data from the database
            
$result $this->db->query($checkQuery);
            
$userData $result->fetch_assoc();
        }
        
        
// Return user data
        
return !empty($userData)?$userData:false;
    }
}

Database and API Configuration (config.php)

In the config.php file, database settings and Github OAuth API configuration constant variables are defined.

Database constants:

  • DB_HOST – Specify the database host.
  • DB_USERNAME – Specify the database username.
  • DB_PASSWORD – Specify the database password.
  • DB_NAME – Specify the database name.
  • DB_USER_TBL – Specify the table name where the user’s account data will be stored.

GitHub API constants:

  • CLIENT_ID – Specify the GitHub App Client ID.
  • CLIENT_SECRET – Specify the GitHub App Client Secret.
  • REDIRECT_URL – Specify the Authorization callback URL.

Call GitHub API:

  • The Github OAuth PHP Client library is used to connect with Github API and working with OAuth client.
  • Initialize Github_OAuth_Client class and pass Client ID, Secret, and Callback URL to connect with Github API and work with SDK.
<?php 
// Database configuration
define('DB_HOST''MySQL_Database_Host');
define('DB_USERNAME''MySQL_Database_Username');
define('DB_PASSWORD''MySQL_Database_Password');
define('DB_NAME''MySQL_Database_Name');
define('DB_USER_TBL''users');

// GitHub API configuration
define('CLIENT_ID''Insert_App_Client_ID');
define('CLIENT_SECRET''Insert_App_Client_Secret');
define('REDIRECT_URL''Callback_URL');

// Start session
if(!session_id()){
    
session_start();
}

// Include Github client library
require_once 'src/Github_OAuth_Client.php';

// Initialize Github OAuth client class
$gitClient = new Github_OAuth_Client(array(
    
'client_id' => CLIENT_ID,
    
'client_secret' => CLIENT_SECRET,
    
'redirect_uri' => REDIRECT_URL
));

// Try to get the access token
if(isset($_SESSION['access_token'])){
    
$accessToken $_SESSION['access_token'];
}

Login & Fetch GitHub Profile Data (index.php)

If the user already logged in with the GitHub account, the profile information (account ID, name, username, email, location, profile picture, and profile link) will display, otherwise, GitHub login button will appear.

  • If the access token already exists in the SESSION, the following happens:
    • The user profile data is retrieved from Github using getAuthenticatedUser() function of Github_OAuth_Client class.
    • Pass profile data in the checkUser() function to insert or update user data in the database.
    • Store the user account data in the SESSION.
    • Show Github profile data to the user.
  • If code parameter exists in the query string of the URL, the following happens:
    • Verify the state to check whether it matches the stored state.
    • Get access token using getAccessToken() function of Github_OAuth_Client class.
    • Store access token in the SESSION.
  • Otherwise:
    • Generate an unguessable random string and store it in the SESSION.
    • Get the OAuth URL using the getAuthorizeURL() function of Github_OAuth_Client class.
    • Render a Github login button on the web page.
<?php 
// Include configuration file
require_once 'config.php';

// Include and initialize user class
require_once 'User.class.php';
$user = new User();

if(isset(
$accessToken)){
    
// Get the user profile data from Github
    
$gitUser $gitClient->getAuthenticatedUser($accessToken);
    
    if(!empty(
$gitUser)){
        
// Getting user profile details
        
$gitUserData = array();
        
$gitUserData['oauth_uid'] = !empty($gitUser->id)?$gitUser->id:'';
        
$gitUserData['name'] = !empty($gitUser->name)?$gitUser->name:'';
        
$gitUserData['username'] = !empty($gitUser->login)?$gitUser->login:'';
        
$gitUserData['email'] = !empty($gitUser->email)?$gitUser->email:'';
        
$gitUserData['location'] = !empty($gitUser->location)?$gitUser->location:'';
        
$gitUserData['picture'] = !empty($gitUser->avatar_url)?$gitUser->avatar_url:'';
        
$gitUserData['link'] = !empty($gitUser->html_url)?$gitUser->html_url:'';
        
        
// Insert or update user data to the database
        
$gitUserData['oauth_provider'] = 'github';
        
$userData $user->checkUser($gitUserData);

        
// Storing user data in the session
        
$_SESSION['userData'] = $userData;

        
// Render Github profile data
        
$output     '<h2>GitHub Account Details</h2>';
        
$output .= '<div class="ac-data">';
        
$output .= '<img src="'.$userData['picture'].'">';
        
$output .= '<p><b>ID:</b> '.$userData['oauth_uid'].'</p>';
        
$output .= '<p><b>Name:</b> '.$userData['name'].'</p>';
        
$output .= '<p><b>Login Username:</b> '.$userData['username'].'</p>';
        
$output .= '<p><b>Email:</b> '.$userData['email'].'</p>';
        
$output .= '<p><b>Location:</b> '.$userData['location'].'</p>';
        
$output .= '<p><b>Profile Link:</b> <a href="'.$userData['link'].'" target="_blank">Click to visit GitHub page</a></p>';
        
$output .= '<p>Logout from <a href="logout.php">GitHub</a></p>';
        
$output .= '</div>';
    }else{
        
$output '<h3 style="color:red">Something went wrong, please try again!</h3>';
    } 
}elseif(isset(
$_GET['code'])){
    
// Verify the state matches the stored state
    
if(!$_GET['state'] || $_SESSION['state'] != $_GET['state']) {
        
header("Location: ".$_SERVER['PHP_SELF']);
    }
    
    
// Exchange the auth code for a token
    
$accessToken $gitClient->getAccessToken($_GET['state'], $_GET['code']);
  
    
$_SESSION['access_token'] = $accessToken;
  
    
header('Location: ./');
}else{
    
// Generate a random hash and store in the session for security
    
$_SESSION['state'] = hash('sha256'microtime(TRUE) . rand() . $_SERVER['REMOTE_ADDR']);
    
    
// Remove access token from the session
    
unset($_SESSION['access_token']);
  
    
// Get the URL to authorize
    
$authUrl $gitClient->getAuthorizeURL($_SESSION['state']);
    
    
// Render Github login button
    
$output '<a href="'.htmlspecialchars($authUrl).'"><img src="images/github-login.png"></a>';
}
?> <div class="container"> <!-- Display login button / GitHub profile information --> <?php echo $output?> </div>

Logout (logout.php)

The logout.php file logs the user out from their Github account.

  • Unset all the SESSION variables (access_token, state, and userData) in PHP.
  • Redirect the user to the homepage.
<?php
// Start session
if(!session_id()){
    
session_start();
}

// Remove access token and state from session
unset($_SESSION['access_token']);
unset(
$_SESSION['state']);

// Remove user data from session
unset($_SESSION['userData']);

// Redirect to the homepage
header("Location:index.php");
?>

Login with Facebook using PHP

Conclusion

Our GitHub OAuth PHP Library helps to integrate Login with Github in PHP. You can easily implement the Github OAuth login system in the web application. Also, the example code functionality can be extended as per your application needs. We also recommend you add other social accounts in the PHP login system for providing a user-friendly way to allow the user to log in to your website.

Do you want to get implementation help, or enhance the functionality of this script? Click here to Submit Service Request

5 Comments

  1. Dave Said...
    • CodexWorld Said...
  2. Justin Said...
  3. Atif Said...
    • CodexWorld Said...

Leave a reply

keyboard_double_arrow_up