Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 41 additions & 6 deletions .docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,51 @@ oauth2.server:
permissionCheck: true
publicKey:
path: "/path/to/public.key"
passPhrase:
permissionCheck: true
grants:
authCode: true
clientCredentials: true
implicit: true
password: true
refreshToken: true
authCode:
ttl: PT1H
clientCredentials:
ttl: PT1H
implicit:
ttl: PT1H
password:
ttl: PT1H
refreshToken:
ttl: P7D
```

### Grant Configuration

Each grant type accepts an object with options. Use empty object `[]` to enable with defaults, or `false` to disable.

**Common option:**
- `ttl` - Access token lifetime (ISO 8601 duration)

**authCode grant:**
- `authCodeTTL` - Authorization code lifetime (default: `PT10M`)
- `codeExchangeProof` - Enable PKCE (default: `false`)

```neon
grants:
authCode:
ttl: PT1H
authCodeTTL: PT5M
codeExchangeProof: true
```

**implicit grant:**
- `accessTokenTTL` - Access token TTL for grant construction (default: `PT10M`)

```neon
grants:
implicit:
ttl: PT2H
accessTokenTTL: PT15M
```

**TTL format** uses [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations): `PT10M` (10 min), `PT1H` (1 hour), `P1D` (1 day), `P7D` (7 days)

For encryption key, you can use `Defuse\Crypt\Key::loadFromAsciiSafeString($string)` or key in a string form.

```neon
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/codesniffer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: "Codesniffer"

on:
pull_request:
workflow_dispatch:

push:
branches: ["*"]
Expand All @@ -12,4 +13,6 @@ on:
jobs:
codesniffer:
name: "Codesniffer"
uses: contributte/.github/.github/workflows/codesniffer.yml@v1
uses: contributte/.github/.github/workflows/codesniffer.yml@master
with:
php: "8.3"
18 changes: 18 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: "Coverage"

on:
pull_request:
workflow_dispatch:

push:
branches: ["*"]

schedule:
- cron: "0 8 * * 1"

jobs:
coverage:
name: "Coverage"
uses: contributte/.github/.github/workflows/nette-tester-coverage-v2.yml@master
with:
php: "8.3"
5 changes: 4 additions & 1 deletion .github/workflows/phpstan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: "Phpstan"

on:
pull_request:
workflow_dispatch:

push:
branches: ["*"]
Expand All @@ -12,4 +13,6 @@ on:
jobs:
phpstan:
name: "Phpstan"
uses: contributte/.github/.github/workflows/phpstan.yml@v1
uses: contributte/.github/.github/workflows/phpstan.yml@master
with:
php: "8.3"
35 changes: 18 additions & 17 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
name: "Nette Tester"
name: "Tests"

on:
pull_request:
workflow_dispatch:

push:
branches: [ "*" ]
branches: ["*"]

schedule:
- cron: "0 8 * * 1"

jobs:
test82:
name: "Nette Tester"
uses: contributte/.github/.github/workflows/nette-tester.yml@v1
test84:
name: "Tests"
uses: contributte/.github/.github/workflows/nette-tester.yml@master
with:
php: "8.2"
php: "8.4"

test81:
name: "Nette Tester"
uses: contributte/.github/.github/workflows/nette-tester.yml@v1
test83:
name: "Tests"
uses: contributte/.github/.github/workflows/nette-tester.yml@master
with:
php: "8.1"
php: "8.3"

test80:
name: "Nette Tester"
uses: contributte/.github/.github/workflows/nette-tester.yml@v1
test82:
name: "Tests"
uses: contributte/.github/.github/workflows/nette-tester.yml@master
with:
php: "8.0"
php: "8.2"

testlower:
name: "Nette Tester"
uses: contributte/.github/.github/workflows/nette-tester.yml@v1
name: "Tests"
uses: contributte/.github/.github/workflows/nette-tester.yml@master
with:
php: "8.0"
php: "8.2"
composer: "composer update --no-interaction --no-progress --prefer-dist --prefer-stable --prefer-lowest"
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ qa: phpstan cs

cs:
ifdef GITHUB_ACTION
vendor/bin/phpcs --standard=ruleset.xml --encoding=utf-8 --colors -nsp -q --report=checkstyle src tests | cs2pr
vendor/bin/phpcs --standard=ruleset.xml --encoding=utf-8 --colors -nsp --extensions=php,phpt -q --report=checkstyle src tests | cs2pr
else
vendor/bin/phpcs --standard=ruleset.xml --encoding=utf-8 --colors -nsp src tests
vendor/bin/phpcs --standard=ruleset.xml --encoding=utf-8 --colors -nsp --extensions=php,phpt src tests
endif

csf:
vendor/bin/phpcbf --standard=ruleset.xml --encoding=utf-8 --colors -nsp src tests
vendor/bin/phpcbf --standard=ruleset.xml --encoding=utf-8 --colors -nsp --extensions=php,phpt src tests

phpstan:
vendor/bin/phpstan analyse -c phpstan.neon
Expand Down
17 changes: 7 additions & 10 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,16 @@
"type": "library",
"license": "MIT",
"require": {
"php": ">=8.1",
"php": ">=8.2",
"league/oauth2-server": "^9.1.0",
"nette/di": "^3.0.14"
"nette/di": "^3.2.2"
},
"require-dev": {
"contributte/psr7-http-message": "^0.9",
"contributte/phpstan": "^0.2.0",
"contributte/qa": "^0.4",
"contributte/psr7-http-message": "^0.10.0",
"contributte/qa": "^0.4.0",
"contributte/tester": "^0.3.0",
"nette/application": "^3.1.8"
},
"conflict": {
"nette/utils": "<3.2.5"
"nette/application": "^3.2.0"
},
"autoload": {
"psr-4": {
Expand All @@ -32,7 +29,7 @@
},
"autoload-dev": {
"psr-4": {
"Tests\\Fixtures\\": "tests/fixtures"
"Tests\\": "tests"
}
},
"minimum-stability": "dev",
Expand All @@ -45,7 +42,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "0.5.x-dev"
"dev-master": "0.6.x-dev"
}
}
}
3 changes: 2 additions & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ includes:

parameters:
level: 9
phpVersion: 80100
phpVersion: 80200

scanDirectories:
- src
Expand All @@ -13,5 +13,6 @@ parameters:

paths:
- src
- .docs

ignoreErrors:
9 changes: 4 additions & 5 deletions ruleset.xml
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="Contributte" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd">
<!-- Rulesets -->
<rule ref="./vendor/contributte/qa/ruleset-8.1.xml"/>
<rule ref="./vendor/contributte/qa/ruleset-8.2.xml"/>

<!-- Rules -->
<rule ref="SlevomatCodingStandard.Files.TypeNameMatchesFileName">
<properties>
<property name="rootNamespaces" type="array">
<element key="src" value="Contributte\OAuth2Server"/>
<element key="tests/mocks" value="Tests\Cases"/>
<element key="tests/fixtures" value="Tests\Fixtures"/>
<element key="tests" value="Tests"/>
</property>
</properties>
</rule>

<!-- Exclude folders -->
<!-- Excludes -->
<exclude-pattern>/tests/tmp</exclude-pattern>
</ruleset>
66 changes: 47 additions & 19 deletions src/DI/OAuth2ServerExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,50 @@ public function getConfigSchema(): Schema
{
return Expect::structure([
'encryptionKey' => Expect::anyOf(Expect::string(), Expect::type(Statement::class)),
'privateKey' => Expect::array([
'path' => Expect::string(),
'passPhrase' => Expect::string(),
'privateKey' => Expect::structure([
'path' => Expect::string()->required(),
'passPhrase' => Expect::string()->nullable(),
'permissionCheck' => Expect::bool(true),
]),
'publicKey' => Expect::array([
'path' => Expect::string(),
])->castTo('array'),
'publicKey' => Expect::structure([
'path' => Expect::string()->required(),
'permissionCheck' => Expect::bool(true),
]),
'grants' => Expect::array([
self::GRANT_AUTH_CODE => Expect::bool(false),
self::GRANT_CLIENT_CREDENTIALS => Expect::bool(false),
self::GRANT_IMPLICIT => Expect::bool(false),
self::GRANT_PASSWORD => Expect::bool(false),
self::GRANT_REFRESH_TOKEN => Expect::bool(false),
]),
])->castTo('array'),
'grants' => Expect::structure([
self::GRANT_AUTH_CODE => Expect::anyOf(
false,
Expect::structure([
'ttl' => Expect::anyOf(Expect::string(), Expect::type(Statement::class))->nullable(),
'authCodeTTL' => Expect::anyOf(Expect::string(), Expect::type(Statement::class))->nullable(),
'codeExchangeProof' => Expect::bool(false),
])->castTo('array'),
)->default(false),
self::GRANT_CLIENT_CREDENTIALS => Expect::anyOf(
false,
Expect::structure([
'ttl' => Expect::anyOf(Expect::string(), Expect::type(Statement::class))->nullable(),
])->castTo('array'),
)->default(false),
self::GRANT_IMPLICIT => Expect::anyOf(
false,
Expect::structure([
'ttl' => Expect::anyOf(Expect::string(), Expect::type(Statement::class))->nullable(),
'accessTokenTTL' => Expect::anyOf(Expect::string(), Expect::type(Statement::class))->nullable(),
])->castTo('array'),
)->default(false),
self::GRANT_PASSWORD => Expect::anyOf(
false,
Expect::structure([
'ttl' => Expect::anyOf(Expect::string(), Expect::type(Statement::class))->nullable(),
])->castTo('array'),
)->default(false),
self::GRANT_REFRESH_TOKEN => Expect::anyOf(
false,
Expect::structure([
'ttl' => Expect::anyOf(Expect::string(), Expect::type(Statement::class))->nullable(),
])->castTo('array'),
)->default(false),
])->castTo('array'),
'responseType' => Expect::type(Statement::class),
]);
}
Expand Down Expand Up @@ -94,11 +122,11 @@ public function loadConfiguration(): void

switch ($grant) {
case self::GRANT_AUTH_CODE:
if (isset($options->codeExchangeProof) && $options->codeExchangeProof === true) {
if (isset($options['codeExchangeProof']) && $options['codeExchangeProof'] === true) {
$grantDefinition->addSetup('enableCodeExchangeProof');
}

$ttl = isset($options->authCodeTTL) && $options->authCodeTTL !== false ? $options->authCodeTTL : 'PT10M';
$ttl = $options['authCodeTTL'] ?? 'PT10M';

if (!$ttl instanceof Statement) {
$ttl = new Statement(DateInterval::class, [$ttl]);
Expand All @@ -112,7 +140,7 @@ public function loadConfiguration(): void
break;

case self::GRANT_IMPLICIT:
$ttl = isset($options->accessTokenTTL) && $options->accessTokenTTL !== false ? $options->accessTokenTTL : 'PT10M';
$ttl = $options['accessTokenTTL'] ?? 'PT10M';

if (!$ttl instanceof Statement) {
$ttl = new Statement(DateInterval::class, [$ttl]);
Expand All @@ -137,12 +165,12 @@ public function loadConfiguration(): void
));
}

$ttl = $options->ttl ?? null;
$ttl = $options['ttl'] ?? null;
if (!$ttl instanceof Statement && $ttl !== null) {
$ttl = new Statement(DateInterval::class, [$ttl]);
}

$authServer->addSetup('revokeRefreshTokens', [false]);
$authServer->addSetup('revokeRefreshTokens', [false]);
$authServer->addSetup('enableGrantType', [$grantDefinition, $ttl]);
}
}
Expand Down
Loading