virgantara/unida-apps-support

A collection of UNIDA Gontor Apps Components.

Maintainers

Package info

github.com/virgantara/Unida-Apps-Support

pkg:composer/virgantara/unida-apps-support

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.7 2026-06-02 03:45 UTC

This package is auto-updated.

Last update: 2026-06-02 03:48:47 UTC


README

License PHP Yii2

A reusable Yii2 component package for UNIDA Gontor applications. This package provides helper components for OAuth2 authentication, token handling, user session integration, and application jump support between UNIDA apps.

๐Ÿ“ฆ Features

  • OAuth2 Authorization Code integration
  • Access token and refresh token management
  • User info retrieval from SSO server
  • Allowed application list retrieval
  • Secure app-to-app jump support
  • Yii2 component-based integration

โš ๏ธ Security Notice

This package must use OAuth2 Authorization Code Flow for authentication and app jumping.

Do not send access_token or refresh_token through URL query parameters.

Bad example:

https://app.example.com/callback?access_token=xxx&refresh_token=yyy

Recommended flow:

Source App
  โ†“
Target App /site/start-sso
  โ†“
SSO /oauth/authorize
  โ†“
Target App /site/auth-callback?code=xxx&state=yyy
  โ†“
Target App exchanges code for token

๐Ÿ“‹ Requirements

  • PHP >= 7.4
  • Yii2 Framework
  • Composer
  • OAuth2 SSO server

โš™๏ธ Installation

1. Add Repository to composer.json

{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/virgantara/Unida-Apps-Support.git"
        }
    ]
}

2. Add Package Requirement

For development branch:

{
    "require": {
        "virgantara/unida-apps-support": "dev-master"
    }
}

For stable release tag:

{
    "require": {
        "virgantara/unida-apps-support": "^1.0"
    }
}

Then run:

composer update -vvv

Or install directly:

composer require virgantara/unida-apps-support:^1.0

๐Ÿ”ง OAuth Configuration

Add this configuration to params.php or params-local.php.

return [
    'oauth' => [
        'client_id' => 'your-client-id',
        'client_secret' => 'your-client-secret',
        'baseurl' => 'https://your-sso-server.com',
        'redirectUri' => 'https://your-app.com/site/auth-callback',
        'scope' => 'read write',
    ],
];

Example:

return [
    'oauth' => [
        'client_id' => 'elitabmas',
        'client_secret' => 'your-secret',
        'baseurl' => 'https://sso.unida.gontor.ac.id',
        'redirectUri' => 'https://elitabmas.unida.gontor.ac.id/site/auth-callback',
        'scope' => 'read write',
    ],
];

๐Ÿงฉ Yii2 Component Configuration

Open config/web.php, then add the components below.

'components' => [
    // Other components...

    'tokenService' => [
        'class' => 'virgantara\components\TokenService',
    ],

    'aplikasi' => [
        'class' => 'virgantara\components\AplikasiAuth',
        'baseurl' => $params['oauth']['baseurl'],
    ],

    'tokenManager' => [
        'class' => 'virgantara\components\TokenManager',
    ],

    'oauth2' => [
        'class' => 'virgantara\components\OAuth2Client',
        'tokenValidationUrl' => $params['oauth']['baseurl'],
        'tokenRefreshUrl' => $params['oauth']['baseurl'],
        'client_id' => $params['oauth']['client_id'],
        'client_secret' => $params['oauth']['client_secret'],
    ],
],

๐Ÿ” Start SSO Login

Add this action to your SiteController.

public function actionStartSso()
{
    $session = Yii::$app->session;

    if (!$session->isActive) {
        $session->open();
    }

    $state = Yii::$app->security->generateRandomString(40);
    $session->set('oauth_state', $state);

    $params = [
        'client_id' => Yii::$app->params['oauth']['client_id'],
        'redirect_uri' => Yii::$app->params['oauth']['redirectUri'],
        'response_type' => 'code',
        'scope' => Yii::$app->params['oauth']['scope'] ?? 'read write',
        'state' => $state,
    ];

    $authUrl = rtrim(Yii::$app->params['oauth']['baseurl'], '/')
        . '/oauth/authorize?'
        . http_build_query($params);

    return $this->redirect($authUrl);
}

๐Ÿ” OAuth Callback

Add this callback action to your SiteController.

public function actionAuthCallback()
{
    try {
        $session = Yii::$app->session;

        if (!$session->isActive) {
            $session->open();
        }

        $sessionState = $session->get('oauth_state');
        $receivedState = Yii::$app->request->get('state');

        if (empty($sessionState) || empty($receivedState) || $sessionState !== $receivedState) {
            throw new \yii\web\BadRequestHttpException('Invalid OAuth state.');
        }

        $authCode = Yii::$app->request->get('code');

        if (empty($authCode)) {
            throw new \yii\web\BadRequestHttpException('Authorization code not received.');
        }

        $response = Yii::$app->tokenManager->fetchAccessTokenWithAuthCode($authCode);

        if (empty($response['access_token'])) {
            throw new \yii\web\UnauthorizedHttpException('Failed to get access token.');
        }

        $accessToken = $response['access_token'];
        $refreshToken = $response['refresh_token'] ?? null;

        $userinfo = Yii::$app->tokenManager->getUserinfo($accessToken);

        if (empty($userinfo) || empty($userinfo['email'])) {
            throw new \yii\web\UnauthorizedHttpException('Failed to get user info.');
        }

        $session->set('access_token', $accessToken);

        if (!empty($refreshToken)) {
            $session->set('refresh_token', $refreshToken);
        }

        /*
         * TODO:
         * Implement local user login here.
         *
         * Example:
         * - Find local user by email
         * - Create user if allowed
         * - Login using Yii::$app->user->login($identity)
         */

        return $this->redirect(['site/index']);
    } catch (\Throwable $e) {
        return $this->handleException($e);
    }
}

Add the exception handler:

protected function handleException($e)
{
    Yii::error($e->getMessage(), __METHOD__);
    Yii::$app->session->setFlash('danger', $e->getMessage());

    return $this->redirect(['site/index']);
}

๐Ÿงญ App-to-App Jump

This package supports Google-like app jumping.

Example:

SIAKAD โ†’ ELITABMAS
E-KHIDMAH โ†’ MOODLE
MOODLE โ†’ SIAKAD

The source app should only open the target app login endpoint:

https://target-app.unida.gontor.ac.id/site/start-sso

The target app will then start its own OAuth2 flow.

Correct flow:

User is logged in to SIAKAD
  โ†“
User clicks ELITABMAS
  โ†“
Browser opens ELITABMAS /site/start-sso
  โ†“
ELITABMAS redirects to SSO /oauth/authorize
  โ†“
SSO detects active SSO session
  โ†“
SSO redirects back to ELITABMAS callback with authorization code
  โ†“
ELITABMAS exchanges code for token
  โ†“
User is logged in to ELITABMAS

The source application must not generate OAuth state for the target application.

๐Ÿ“ฑ Allowed Apps List

You can render allowed applications from SSO using:

$apps = Yii::$app->aplikasi->getRenderedAllowedAppsList();

Example usage in layout or menu:

use yii\widgets\Menu;

echo Menu::widget([
    'items' => Yii::$app->aplikasi->getRenderedAllowedAppsList(),
    'encodeLabels' => false,
]);

The SSO /app/list endpoint should return data like this:

[
    {
        "app_id": 1,
        "client_id": "siakad",
        "app_name": "SIAKAD",
        "base_url": "https://siakad.unida.gontor.ac.id",
        "jump_callback": "/site/start-sso"
    },
    {
        "app_id": 2,
        "client_id": "elitabmas",
        "app_name": "ELITABMAS",
        "base_url": "https://elitabmas.unida.gontor.ac.id",
        "jump_callback": "/site/start-sso"
    }
]

Or preferably:

[
    {
        "app_id": 2,
        "client_id": "elitabmas",
        "app_name": "ELITABMAS",
        "start_sso_url": "https://elitabmas.unida.gontor.ac.id/site/start-sso"
    }
]

๐Ÿšช Logout

Recommended logout flow:

Application logout
  โ†“
Clear local Yii2 session
  โ†“
Redirect to SSO logout endpoint
  โ†“
SSO clears global SSO session
  โ†“
Redirect back to application logout callback

Example:

public function actionLogout()
{
    Yii::$app->user->logout();

    Yii::$app->session->remove('access_token');
    Yii::$app->session->remove('refresh_token');

    $logoutUrl = rtrim(Yii::$app->params['oauth']['baseurl'], '/')
        . '/oauth/logout?'
        . http_build_query([
            'client_id' => Yii::$app->params['oauth']['client_id'],
        ]);

    return $this->redirect($logoutUrl);
}

๐Ÿท๏ธ Release Tag Procedure

Use semantic versioning for releases.

Format:

MAJOR.MINOR.PATCH

Examples:

v1.0.0
v1.0.1
v1.1.0
v2.0.0

1. Check Current Branch

git branch

Switch to master or main branch:

git checkout master

or:

git checkout main

2. Pull Latest Changes

git pull origin master

or:

git pull origin main

3. Check Git Status

git status

Make sure there are no uncommitted changes.

4. Commit Changes

git add .
git commit -m "Prepare release v1.0.0"

Skip this step if all changes have already been committed.

5. Create Git Tag

git tag -a v1.0.0 -m "Release v1.0.0"

6. Push Commit and Tag

If using master:

git push origin master
git push origin v1.0.0

If using main:

git push origin main
git push origin v1.0.0

Or push all tags:

git push origin --tags

7. Verify Tag

git tag

Or check remote tags:

git ls-remote --tags origin

๐Ÿ“ฆ Using a Release Tag in Yii2 App

After creating a release tag, update the Yii2 app composer.json.

{
    "require": {
        "virgantara/unida-apps-support": "^1.0"
    }
}

Then run:

composer update virgantara/unida-apps-support -vvv

For a specific version:

{
    "require": {
        "virgantara/unida-apps-support": "1.0.0"
    }
}

Then:

composer update virgantara/unida-apps-support -vvv

๐Ÿ”„ Updating Release Version

For bug fixes:

git tag -a v1.0.1 -m "Release v1.0.1"
git push origin v1.0.1

For new backward-compatible features:

git tag -a v1.1.0 -m "Release v1.1.0"
git push origin v1.1.0

For breaking changes:

git tag -a v2.0.0 -m "Release v2.0.0"
git push origin v2.0.0

๐Ÿงน Removing a Wrong Tag

Remove local tag:

git tag -d v1.0.0

Remove remote tag:

git push origin --delete v1.0.0

Create the corrected tag again:

git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0

๐Ÿงช Testing Package Installation Locally

In a Yii2 application:

composer clear-cache
composer update virgantara/unida-apps-support -vvv

Check installed version:

composer show virgantara/unida-apps-support

๐Ÿ“ Suggested Package Structure

Unida-Apps-Support/
โ”œโ”€โ”€ composer.json
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ src/
โ”‚   โ””โ”€โ”€ components/
โ”‚       โ”œโ”€โ”€ AplikasiAuth.php
โ”‚       โ”œโ”€โ”€ OAuth2Client.php
โ”‚       โ”œโ”€โ”€ TokenManager.php
โ”‚       โ””โ”€โ”€ TokenService.php
โ””โ”€โ”€ LICENSE

๐Ÿงพ Example Package composer.json

{
    "name": "virgantara/unida-apps-support",
    "description": "Support components for Yii2 UNIDA Gontor applications",
    "type": "yii2-extension",
    "license": "MIT",
    "authors": [
        {
            "name": "Oddy Virgantara Putra",
            "email": "your-email@example.com"
        }
    ],
    "require": {
        "php": ">=7.4",
        "yiisoft/yii2": "~2.0.0",
        "yiisoft/yii2-httpclient": "*",
        "firebase/php-jwt": "^6.0"
    },
    "autoload": {
        "psr-4": {
            "virgantara\\": "src/"
        }
    }
}

If your component files are placed directly under:

components/

then use:

{
    "autoload": {
        "psr-4": {
            "virgantara\\": ""
        }
    }
}

โœ… Recommended Release Checklist

Before creating a new tag:

  • Code is committed
  • composer.json is valid
  • Namespace matches PSR-4 autoload
  • README is updated
  • No token is exposed through URL
  • OAuth callback uses authorization code
  • App jump uses target app /site/start-sso
  • Version tag is created
  • Tag is pushed to GitHub
  • Yii2 app can install the tagged version

๐Ÿ“„ License

This package is open-sourced under the MIT license.