PHPackages                             alex-kalanis/oauth2 - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [DevOps &amp; Deployment](/categories/devops)
4. /
5. alex-kalanis/oauth2

ActiveLibrary[DevOps &amp; Deployment](/categories/devops)

alex-kalanis/oauth2
===================

Nette OAuth2 Provider bundle

v1.0.1(1y ago)0381BSD-3-ClausePHPPHP &gt;= 8.1.0

Since Dec 25Pushed 1y ago1 watchersCompare

[ Source](https://github.com/alex-kalanis/oauth2)[ Packagist](https://packagist.org/packages/alex-kalanis/oauth2)[ RSS](/packages/alex-kalanis-oauth2/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (2)Dependencies (16)Versions (3)Used By (1)

OAuth2 Provider
===============

[](#oauth2-provider)

[![Build Status](https://github.com/alex-kalanis/oauth2/actions/workflows/code_checks.yml/badge.svg)](https://github.com/alex-kalanis/oauth2/actions/workflows/code_checks.yml/badge.svg)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/3078726c8b50ac5629773594d75ba2efb735a0e0a58cddb4de2f4b2769337675/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f616c65782d6b616c616e69732f6f61757468322f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/alex-kalanis/oauth2/?branch=master)[![Latest Stable Version](https://camo.githubusercontent.com/54bab132cfa8050f37b6868749679dde6640cc641618c69637bc9d806977a559/68747470733a2f2f706f7365722e707567782e6f72672f616c65782d6b616c616e69732f6f61757468322f762f737461626c652e7376673f763d31)](https://packagist.org/packages/alex-kalanis/oauth2)[![Minimum PHP Version](https://camo.githubusercontent.com/183804d09fec16ca7b6209b007250b7d8db1b915042feb093a9f20e6e1f25359/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344253230382e312d3838393242462e737667)](https://php.net/)[![Downloads](https://camo.githubusercontent.com/17f25110b2e373b1ff560bc65cbcfe6ebf4855c4a39fe866e22bde8a1ae07f84/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f616c65782d6b616c616e69732f6f61757468322e7376673f7631)](https://packagist.org/packages/alex-kalanis/oauth2)[![License](https://camo.githubusercontent.com/38efa51d9a20af92c22dcccdd3e4833d14d1688f6bb89f70466c925856851f38/68747470733a2f2f706f7365722e707567782e6f72672f616c65782d6b616c616e69732f6f61757468322f6c6963656e73652e7376673f763d31)](https://packagist.org/packages/alex-kalanis/oauth2)[![Code Coverage](https://camo.githubusercontent.com/b5112640fb677408c1918ac0a56aaa7f60f21aa28661db22440cc83d9c06a790/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f616c65782d6b616c616e69732f6f61757468322f6261646765732f636f7665726167652e706e673f623d6d617374657226763d31)](https://scrutinizer-ci.com/g/alex-kalanis/oauth2/?branch=master)

This is repository for adding OAuth into Nette. Fork of older Drahak repository with refactor to run on php 8.1+.

The main difference is in directory structure, namespaces, tests, static analysis and dependency check.

This package also supports multiple storages. With a few simple steps (implementing own version and extending configuration) you can add another storage. Currently available are Nette DB and Dibi.

Requirements
------------

[](#requirements)

kalanis/OAuth2 requires PHP version 8.1.0 or higher. The only production dependency is [Nette framework 3.2.x](http://www.nette.org).

But for php8.1 you probably need to add [`SensitiveParameter`](https://www.php.net/manual/en/class.sensitiveparameter.php)attribute class into your bootstrap. The example is in Tests.

Installation &amp; setup
------------------------

[](#installation--setup)

The easiest way is to use [Composer](http://doc.nette.org/en/composer)

```
$ composer require alex-kalanis/oauth2
```

Then add following code to your app bootstrap file before creating container:

```
kalanis\OAuth2\DI\Extension::install($configurator);
```

Neon configuration
------------------

[](#neon-configuration)

```
oauth2:
	accessTokenLifetime: 3600 # 1 hour
	refreshTokenLifetime: 36000 # 10 hours
	authorizationCodeLifetime: 360 # 6 minutes
	storage: 'ndb' # currently allowed values: 'ndb', 'dibi'
	accessTokenStorage: 'kalanis\OAuth2\Storage\NDB\AccessTokenStorage'
	authorizationCodeStorage: 'kalanis\OAuth2\Storage\NDB\AuthorizationCodeStorage'
	clientStorage: 'kalanis\OAuth2\Storage\NDB\ClientStorage'
	refreshTokenStorage: 'kalanis\OAuth2\Storage\NDB\RefreshTokenStorage'
```

- `accessTokenLifetime` - access token lifetime in seconds
- `refreshTokenLifetime` - refresh token lifetime in seconds
- `authorizationCodeLifetime` - authorization code lifetime in seconds
- `storage` - storage will switch between default NDB and dibi storage. You can use your storage for each storage part.

OAuth2
------

[](#oauth2)

#### [Abstract protocol flow](http://tools.ietf.org/html/rfc6749#section-1.2)

[](#abstract-protocol-flow)

```
     +--------+                               +---------------+
     |        |------ Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        || Authorization |
     | Client |                               |     Server    |
     |        ||    Resource   |
     |        |                               |     Server    |
     |        |user->isLoggedIn()) {
            $this->redirect('AnyUser:login', array('backlink' => $this->storeRequest()));
        }

        if ($response_type == 'code') {
            $this->issueAuthorizationCode($response_type, $redirect_uri, $scope);
        } else if ($response_type == 'token') {
            $this->issueAccessToken(IGrant::IMPLICIT, $redirect_uri);
        }
    }

    /**
     * Access token provider
     */
    public function actionToken(): void
    {
        try {
            $this->issueAccessToken();
        } catch (OAuthException $e) {
            $this->oauthError($e);
        }
    }

}
```

Method `issueAccessToken` determines correct grant type from `grant_type` parameter. In case of error throws some `OAuthException` which can be handled by `oauthError`method in default implementation.

Action `authorize` is more complex. This is used for generating Authorization code (see below - [Authorization code](#authorization-code)) but for Implicit grant type it's necessary to generate access token here. In case if user is not logged in, redirect user to some login page and then restore authorization request using backlink.

Grant types
-----------

[](#grant-types)

Are determined by `grant_type` parameter. There is support of base grant types as defined in OAuth2 specification: Authorization Code, Implicit, Password, Client Credentials and Refresh token.

1. Authorization code

---

This grant type is great for third-party applications which can secure client secret code.

To generate access token, you'll need to get authorization code first. You can obtain it from `IOAuthPresenter` by calling `issueAuthorizationCode`.

##### Request for authorization code:

[](#request-for-authorization-code)

```
GET //oauth.presenter.url/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=email

```

- \[REQUIRED\] **response\_type** - you want to generate authorization `code`
- \[REQUIRED\] **client\_id** - client ID (e.g. application) that requests for access token
- \[REQUIRED\] **redirect\_uri** - URL address whereto redirect in case of success or error
- \[OPTIONAL\] **scope** - specify the scope of access request

##### Authorization code response:

[](#authorization-code-response)

In any case (error or success) Resource owner redirects back to the client using `redirect_uri` with authorization code as a query parameter:

```
//redirect_uri/?code=AnlSCIWYbchsCc5sdc5ac4caca8a2

```

Or

```
//redirect_uri/?error=unauthorized_client&error_description=Client+is+not+found

```

Since you have authorization code you can make access token request (data provided as `application/x-www-form-urlencoded`).

##### Request for access token:

[](#request-for-access-token)

```
POST //oauth.presenter.url/token
	grant_type=authorization_code
	&code=AUTHORIZATION_CODE
	&client_id=CLIENT_ID
	&client_secret=CLIENT_SECRET

```

- \[REQUIRED\] **grant\_type** - this parameter says OAuth to use Authorization code
- \[REQUIRED\] **code** - authorization code which you got from Resource owner
- \[REQUIRED\] **client\_id** - client ID (e.g. application) that requests for access token
- \[REQUIRED\] **client\_secret** - client (e.g. application) secret key that requests for access token

##### Access token response

[](#access-token-response)

```
{
	"access_token": "AnlSCIWYbchsCc5sdc5ac4caca8a2",
	"token_type": "bearer",
	"expires_in": 3600,
	"refresh_token": "DS6SA512ADCVa51adc54VDS51VD5"
}

```

In case or error, provides JSON response:

```
{
	"error": "invalid_request",
	"error_description": "Invalid authorization code"
}

```

2. Implicit

---

Is used for browser-based (web) or mobile applications, where you can't secure client secret so yopu can't use it to obtain access token.

##### Request for access token:

[](#request-for-access-token-1)

```
GET //oauth.presenter.url/authorization?response_type=token&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=email

```

- \[REQUIRED\] **response\_type** - since you request access token from Resource owner, you must tell you want an access token (not authorization code)
- \[REQUIRED\] **client\_id** - client ID (e.g. application) that requests for access token
- \[REQUIRED\] **redirect\_uri** - URL where to redirect in case of success or error
- \[OPTIONAL\] **scope** - specify the scope of access request

##### Access token response

[](#access-token-response-1)

Redirect to `redirect_uri`

```
//redirect_uri/#access_token=AnlSCIWYbchsCc5sdc5ac4caca8a2&expires_in=3600&token_type=bearer

```

In case or error, redirects to:

```
//redirect_uri/#error=unauthorized_client&error_description=Client+is+not+found

```

3. Password

---

Is used for trusted (usually first-party) applications, where you completely trust client because you generate access token from real user credentials (username, password)

##### Request for access token:

[](#request-for-access-token-2)

```
POST //oauth.presenter.url/token
	grant_type=password
	&username=USERNAME
	&password=PASSWORD
	&client_id=CLIENT_ID

```

- \[REQUIRED\] **grant\_type** - Password grant type uses identifier (so unexpectedly) `password`
- \[REQUIRED\] **client\_id** - client ID (e.g. application) that requests for access token
- \[REQUIRED\] **username** - real user's username
- \[OPTIONAL\] **password** - real user's password

##### Access token response

[](#access-token-response-2)

```
{
	"access_token": "AnlSCIWYbchsCc5sdc5ac4caca8a2",
	"token_type": "bearer",
	"expires_in": 3600,
	"refresh_token": "DS6SA512ADCVa51adc54VDS51VD5"
}

```

In case or error:

```
{
	"error": "invalid_request",
	"error_description": "Invalid authorization code"
}

```

4. Client credentials

---

If application needs to get access token for their own account outside the context of any specific user this is probably the best way.

##### Request for access token:

[](#request-for-access-token-3)

```
POST //oauth.presenter.url/token
	grant_type=client_credentials
	&client_id=CLIENT_ID
	&client_SECRET=CLIENT_SECRET

```

- \[REQUIRED\] **grant\_type** - Password grant type uses identifier (so unexpectedly) `password`
- \[REQUIRED\] **client\_id** - client ID (e.g. application) that requests for access token
- \[REQUIRED\] **client\_secret** - client (e.g. application) secret key that requests for access token

##### Access token response

[](#access-token-response-3)

```
{
	"access_token": "AnlSCIWYbchsCc5sdc5ac4caca8a2",
	"token_type": "bearer",
	"expires_in": 3600,
	"refresh_token": "DS6SA512ADCVa51adc54VDS51VD5"
}

```

In case or error:

```
{
	"error": "invalid_request",
	"error_description": "Invalid authorization code"
}

```

5. Refresh token

---

Is used to restore (actually re-generate) access token without authentication process. Refresh token is provided with almost every grant type (excluding Implicit).

##### Request for refresh token:

[](#request-for-refresh-token)

```
POST //oauth.presenter.url/token
	grant_type=refresh_token
	&refresh_token=DS6SA512ADCVa51adc54VDS51VD5
	&client_id=CLIENT_ID

```

- \[REQUIRED\] **grant\_type** - Refresh token identifier
- \[REQUIRED\] **refresh\_token** - refresh token itself, that you got from almost any access token
- \[REQUIRED\] **client\_id** - client ID (e.g. application) that requests for access token

##### Access token response

[](#access-token-response-4)

```
{
	"access_token": "AnlSCIWYbchsCc5sdc5ac4caca8a2",
	"token_type": "bearer",
	"expires_in": 3600,
	"refresh_token": "DS6SA512ADCVa51adc54VDS51VD5"
}

```

In case or error:

```
{
	"error": "invalid_request",
	"error_description": "Invalid refresh token"
}

```

### Subnotes:

[](#subnotes)

I run this locally on my own Docker instances which was based on phpdocker.io. So you do not see the whole project. I also have my private tasks for it which aren't part of the repository.

###  Health Score

29

—

LowBetter than 59% of packages

Maintenance40

Moderate activity, may be stable

Popularity7

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 53% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

2

Last Release

506d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/499b0a541b787cdb31412f578c7b94c9790bcbee7de12c65b6101c6ce45ef6f0?d=identicon)[alex-kalanis](/maintainers/alex-kalanis)

---

Top Contributors

[![drahak](https://avatars.githubusercontent.com/u/1215810?v=4)](https://github.com/drahak "drahak (35 commits)")[![alex-kalanis](https://avatars.githubusercontent.com/u/59184183?v=4)](https://github.com/alex-kalanis "alex-kalanis (15 commits)")[![marten-cz](https://avatars.githubusercontent.com/u/582397?v=4)](https://github.com/marten-cz "marten-cz (8 commits)")[![jspetrak](https://avatars.githubusercontent.com/u/146057?v=4)](https://github.com/jspetrak "jspetrak (4 commits)")[![vymak](https://avatars.githubusercontent.com/u/3403705?v=4)](https://github.com/vymak "vymak (4 commits)")

---

Tags

netteserverprovideroauth2drahak

###  Code Quality

Static AnalysisRector

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/alex-kalanis-oauth2/health.svg)

```
[![Health](https://phpackages.com/badges/alex-kalanis-oauth2/health.svg)](https://phpackages.com/packages/alex-kalanis-oauth2)
```

###  Alternatives

[nette/web-project

Nette: Standard Web Project

10991.8k](/packages/nette-web-project)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
