Merge pull request #784 from appwrite/feat-511-jwt-support
Feat 511 jwt support
This commit is contained in:
commit
3daa99ea53
9 changed files with 382 additions and 109 deletions
|
@ -1,5 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Ahc\Jwt\JWT;
|
||||||
use Utopia\App;
|
use Utopia\App;
|
||||||
use Utopia\Exception;
|
use Utopia\Exception;
|
||||||
use Utopia\Config\Config;
|
use Utopia\Config\Config;
|
||||||
|
@ -637,6 +638,49 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||||
;
|
;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
App::post('/v1/account/jwt')
|
||||||
|
->desc('Create Account JWT')
|
||||||
|
->groups(['api', 'account'])
|
||||||
|
->label('scope', 'account')
|
||||||
|
->label('sdk.platform', [APP_PLATFORM_CLIENT])
|
||||||
|
->label('sdk.namespace', 'account')
|
||||||
|
->label('sdk.method', 'createJWT')
|
||||||
|
->label('sdk.description', '/docs/references/account/create-jwt.md')
|
||||||
|
->label('abuse-limit', 10)
|
||||||
|
->label('abuse-key', 'url:{url},userId:{param-userId}')
|
||||||
|
->inject('response')
|
||||||
|
->inject('user')
|
||||||
|
->action(function ($response, $user) {
|
||||||
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
|
/** @var Appwrite\Database\Document $user */
|
||||||
|
|
||||||
|
$tokens = $user->getAttribute('tokens', []);
|
||||||
|
$session = new Document();
|
||||||
|
|
||||||
|
foreach ($tokens as $token) { /** @var Appwrite\Database\Document $token */
|
||||||
|
if ($token->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too
|
||||||
|
$session = $token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($session->isEmpty()) {
|
||||||
|
throw new Exception('No valid session found', 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
$jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
|
||||||
|
|
||||||
|
$response
|
||||||
|
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||||
|
->dynamic(new Document(['jwt' => $jwt->encode([
|
||||||
|
// 'uid' => 1,
|
||||||
|
// 'aud' => 'http://site.com',
|
||||||
|
// 'scopes' => ['user'],
|
||||||
|
// 'iss' => 'http://api.mysite.com',
|
||||||
|
'userId' => $user->getId(),
|
||||||
|
'sessionId' => $session->getId(),
|
||||||
|
])]), Response::MODEL_JWT);
|
||||||
|
});
|
||||||
|
|
||||||
App::get('/v1/account')
|
App::get('/v1/account')
|
||||||
->desc('Get Account')
|
->desc('Get Account')
|
||||||
->groups(['api', 'account'])
|
->groups(['api', 'account'])
|
||||||
|
|
|
@ -165,14 +165,17 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo
|
||||||
$scope = $route->getLabel('scope', 'none'); // Allowed scope for chosen route
|
$scope = $route->getLabel('scope', 'none'); // Allowed scope for chosen route
|
||||||
$scopes = $roles[$role]['scopes']; // Allowed scopes for user role
|
$scopes = $roles[$role]['scopes']; // Allowed scopes for user role
|
||||||
|
|
||||||
|
$authKey = $request->getHeader('x-appwrite-key', '');
|
||||||
|
|
||||||
|
if (!empty($authKey)) { // API Key authentication
|
||||||
// Check if given key match project API keys
|
// Check if given key match project API keys
|
||||||
$key = $project->search('secret', $request->getHeader('x-appwrite-key', ''), $project->getAttribute('keys', []));
|
$key = $project->search('secret', $authKey, $project->getAttribute('keys', []));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try app auth when we have project key and no user
|
* Try app auth when we have project key and no user
|
||||||
* Mock user to app and grant API key scopes in addition to default app scopes
|
* Mock user to app and grant API key scopes in addition to default app scopes
|
||||||
*/
|
*/
|
||||||
if (null !== $key && $user->isEmpty()) {
|
if ($key && $user->isEmpty()) {
|
||||||
$user = new Document([
|
$user = new Document([
|
||||||
'$id' => '',
|
'$id' => '',
|
||||||
'status' => Auth::USER_STATUS_ACTIVATED,
|
'status' => Auth::USER_STATUS_ACTIVATED,
|
||||||
|
@ -186,6 +189,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo
|
||||||
|
|
||||||
Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys.
|
Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys.
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($user->getId()) {
|
if ($user->getId()) {
|
||||||
Authorization::setRole('user:'.$user->getId());
|
Authorization::setRole('user:'.$user->getId());
|
||||||
|
|
25
app/init.php
25
app/init.php
|
@ -11,6 +11,8 @@ if (\file_exists(__DIR__.'/../vendor/autoload.php')) {
|
||||||
require_once __DIR__.'/../vendor/autoload.php';
|
require_once __DIR__.'/../vendor/autoload.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use Ahc\Jwt\JWT;
|
||||||
|
use Ahc\Jwt\JWTException;
|
||||||
use Appwrite\Auth\Auth;
|
use Appwrite\Auth\Auth;
|
||||||
use Appwrite\Database\Database;
|
use Appwrite\Database\Database;
|
||||||
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
|
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
|
||||||
|
@ -412,6 +414,29 @@ App::setResource('user', function($mode, $project, $console, $request, $response
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$authJWT = $request->getHeader('x-appwrite-jwt', '');
|
||||||
|
|
||||||
|
if (!empty($authJWT)) { // JWT authentication
|
||||||
|
$jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
|
||||||
|
|
||||||
|
try {
|
||||||
|
$payload = $jwt->decode($authJWT);
|
||||||
|
} catch (JWTException $error) {
|
||||||
|
throw new Exception('Failed to verify JWT. '.$error->getMessage(), 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
$jwtUserId = $payload['userId'] ?? '';
|
||||||
|
$jwtSessionId = $payload['sessionId'] ?? '';
|
||||||
|
|
||||||
|
if($jwtUserId && $jwtSessionId) {
|
||||||
|
$user = $projectDB->getDocument($jwtUserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($user->search('$id', $jwtSessionId, $user->getAttribute('tokens')))) { // Match JWT to active token
|
||||||
|
$user = new Document(['$id' => '', '$collection' => Database::SYSTEM_COLLECTION_USERS]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $user;
|
return $user;
|
||||||
}, ['mode', 'project', 'console', 'request', 'response', 'projectDB', 'consoleDB']);
|
}, ['mode', 'project', 'console', 'request', 'response', 'projectDB', 'consoleDB']);
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,8 @@
|
||||||
"domnikl/statsd": "3.0.2",
|
"domnikl/statsd": "3.0.2",
|
||||||
"influxdb/influxdb-php": "1.15.1",
|
"influxdb/influxdb-php": "1.15.1",
|
||||||
"phpmailer/phpmailer": "6.1.7",
|
"phpmailer/phpmailer": "6.1.7",
|
||||||
"chillerlan/php-qrcode": "4.3.0"
|
"chillerlan/php-qrcode": "4.3.0",
|
||||||
|
"adhocore/jwt": "1.1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"swoole/ide-helper": "4.5.5",
|
"swoole/ide-helper": "4.5.5",
|
||||||
|
|
233
composer.lock
generated
233
composer.lock
generated
|
@ -4,8 +4,65 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "249dc088c5f9f74a1c0e91661f93f96b",
|
"content-hash": "2a235acbc30e22872101713bf3602351",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "adhocore/jwt",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/adhocore/php-jwt.git",
|
||||||
|
"reference": "424a1d66b729a316dd074e6382167765b810cd3d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/adhocore/php-jwt/zipball/424a1d66b729a316dd074e6382167765b810cd3d",
|
||||||
|
"reference": "424a1d66b729a316dd074e6382167765b810cd3d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^6.5 || ^7.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Ahc\\Jwt\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Jitendra Adhikari",
|
||||||
|
"email": "jiten.adhikary@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Ultra lightweight JSON web token (JWT) library for PHP5.5+.",
|
||||||
|
"keywords": [
|
||||||
|
"auth",
|
||||||
|
"json-web-token",
|
||||||
|
"jwt",
|
||||||
|
"jwt-auth",
|
||||||
|
"jwt-php",
|
||||||
|
"token"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/adhocore/php-jwt/issues",
|
||||||
|
"source": "https://github.com/adhocore/php-jwt/tree/1.1.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://paypal.me/ji10",
|
||||||
|
"type": "custom"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2020-10-09T00:34:35+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "appwrite/php-clamav",
|
"name": "appwrite/php-clamav",
|
||||||
"version": "v1.0.1",
|
"version": "v1.0.1",
|
||||||
|
@ -1702,23 +1759,23 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/amphp/amp.git",
|
"url": "https://github.com/amphp/amp.git",
|
||||||
"reference": "efca2b32a7580087adb8aabbff6be1dc1bb924a9"
|
"reference": "7d4bbc6e0b47c6bb39b6cce1a4b5942e0c5125fb"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/amphp/amp/zipball/efca2b32a7580087adb8aabbff6be1dc1bb924a9",
|
"url": "https://api.github.com/repos/amphp/amp/zipball/7d4bbc6e0b47c6bb39b6cce1a4b5942e0c5125fb",
|
||||||
"reference": "efca2b32a7580087adb8aabbff6be1dc1bb924a9",
|
"reference": "7d4bbc6e0b47c6bb39b6cce1a4b5942e0c5125fb",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7"
|
"php": ">=7.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"amphp/php-cs-fixer-config": "dev-master",
|
"amphp/php-cs-fixer-config": "dev-master",
|
||||||
"amphp/phpunit-util": "^1",
|
"amphp/phpunit-util": "^1",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"jetbrains/phpstorm-stubs": "^2019.3",
|
"jetbrains/phpstorm-stubs": "^2019.3",
|
||||||
"phpunit/phpunit": "^6.0.9 | ^7",
|
"phpunit/phpunit": "^7 | ^8 | ^9",
|
||||||
"psalm/phar": "^3.11@dev",
|
"psalm/phar": "^3.11@dev",
|
||||||
"react/promise": "^2"
|
"react/promise": "^2"
|
||||||
},
|
},
|
||||||
|
@ -1776,7 +1833,7 @@
|
||||||
"support": {
|
"support": {
|
||||||
"irc": "irc://irc.freenode.org/amphp",
|
"irc": "irc://irc.freenode.org/amphp",
|
||||||
"issues": "https://github.com/amphp/amp/issues",
|
"issues": "https://github.com/amphp/amp/issues",
|
||||||
"source": "https://github.com/amphp/amp/tree/v2.5.2"
|
"source": "https://github.com/amphp/amp/tree/master"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -1784,7 +1841,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-10T17:06:37+00:00"
|
"time": "2021-01-13T19:16:50+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "amphp/byte-stream",
|
"name": "amphp/byte-stream",
|
||||||
|
@ -3102,12 +3159,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||||
"reference": "cdb8225b328ef5e9647049954299211804000ce0"
|
"reference": "0837b6d36db129e8e9478d39f2f2cd9e40eaef97"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cdb8225b328ef5e9647049954299211804000ce0",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/0837b6d36db129e8e9478d39f2f2cd9e40eaef97",
|
||||||
"reference": "cdb8225b328ef5e9647049954299211804000ce0",
|
"reference": "0837b6d36db129e8e9478d39f2f2cd9e40eaef97",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3155,7 +3212,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:22:20+00:00"
|
"time": "2021-01-14T08:06:22+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-invoker",
|
"name": "phpunit/php-invoker",
|
||||||
|
@ -3163,12 +3220,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-invoker.git",
|
"url": "https://github.com/sebastianbergmann/php-invoker.git",
|
||||||
"reference": "6fdda2828180f7d86cf66d822e6ad4bc124baf5d"
|
"reference": "cc5d70ab3d26c07ca2c5a7edaa4df1b64ffce737"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/6fdda2828180f7d86cf66d822e6ad4bc124baf5d",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/cc5d70ab3d26c07ca2c5a7edaa4df1b64ffce737",
|
||||||
"reference": "6fdda2828180f7d86cf66d822e6ad4bc124baf5d",
|
"reference": "cc5d70ab3d26c07ca2c5a7edaa4df1b64ffce737",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3219,7 +3276,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:22:25+00:00"
|
"time": "2021-01-14T08:06:31+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-text-template",
|
"name": "phpunit/php-text-template",
|
||||||
|
@ -3227,12 +3284,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-text-template.git",
|
"url": "https://github.com/sebastianbergmann/php-text-template.git",
|
||||||
"reference": "081fc9efc54b1b858b3497c142d82a0c36bc6755"
|
"reference": "4bf8e2b779618907e744fd8c221a669d481ae522"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/081fc9efc54b1b858b3497c142d82a0c36bc6755",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/4bf8e2b779618907e744fd8c221a669d481ae522",
|
||||||
"reference": "081fc9efc54b1b858b3497c142d82a0c36bc6755",
|
"reference": "4bf8e2b779618907e744fd8c221a669d481ae522",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3279,7 +3336,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:22:47+00:00"
|
"time": "2021-01-14T08:07:09+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-timer",
|
"name": "phpunit/php-timer",
|
||||||
|
@ -3287,12 +3344,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-timer.git",
|
"url": "https://github.com/sebastianbergmann/php-timer.git",
|
||||||
"reference": "2194371fec37b03cfda3f8ab08aee33787350228"
|
"reference": "5b6fb138e2bba0d33bc043ccfc58caa585a1b666"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2194371fec37b03cfda3f8ab08aee33787350228",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5b6fb138e2bba0d33bc043ccfc58caa585a1b666",
|
||||||
"reference": "2194371fec37b03cfda3f8ab08aee33787350228",
|
"reference": "5b6fb138e2bba0d33bc043ccfc58caa585a1b666",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3339,7 +3396,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:22:31+00:00"
|
"time": "2021-01-14T08:06:40+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit",
|
"name": "phpunit/phpunit",
|
||||||
|
@ -3504,12 +3561,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/cli-parser.git",
|
"url": "https://github.com/sebastianbergmann/cli-parser.git",
|
||||||
"reference": "1012bd8df812778b8386c5e76cacd85b45cf329e"
|
"reference": "b9d0154b00cd0c232d2fb04c7a41aef04a3ef388"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/1012bd8df812778b8386c5e76cacd85b45cf329e",
|
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/b9d0154b00cd0c232d2fb04c7a41aef04a3ef388",
|
||||||
"reference": "1012bd8df812778b8386c5e76cacd85b45cf329e",
|
"reference": "b9d0154b00cd0c232d2fb04c7a41aef04a3ef388",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3553,7 +3610,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:23:03+00:00"
|
"time": "2021-01-14T08:07:37+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/code-unit",
|
"name": "sebastian/code-unit",
|
||||||
|
@ -3617,12 +3674,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
|
"url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
|
||||||
"reference": "f0a408b6519db241e624a62576dc5871d4ac8c14"
|
"reference": "e9fb7de0109de478aa512d6001b95c9111259cb4"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/f0a408b6519db241e624a62576dc5871d4ac8c14",
|
"url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/e9fb7de0109de478aa512d6001b95c9111259cb4",
|
||||||
"reference": "f0a408b6519db241e624a62576dc5871d4ac8c14",
|
"reference": "e9fb7de0109de478aa512d6001b95c9111259cb4",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3665,7 +3722,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:21:36+00:00"
|
"time": "2021-01-14T08:05:02+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/comparator",
|
"name": "sebastian/comparator",
|
||||||
|
@ -3673,12 +3730,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/comparator.git",
|
"url": "https://github.com/sebastianbergmann/comparator.git",
|
||||||
"reference": "fe4c68c639d9e580ec31bfc88b32641dc80a08d0"
|
"reference": "1803ef9c6631bec96ba12adb392d9bdd80bffccc"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fe4c68c639d9e580ec31bfc88b32641dc80a08d0",
|
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1803ef9c6631bec96ba12adb392d9bdd80bffccc",
|
||||||
"reference": "fe4c68c639d9e580ec31bfc88b32641dc80a08d0",
|
"reference": "1803ef9c6631bec96ba12adb392d9bdd80bffccc",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3740,7 +3797,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:21:42+00:00"
|
"time": "2021-01-14T08:05:14+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/complexity",
|
"name": "sebastian/complexity",
|
||||||
|
@ -3748,12 +3805,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/complexity.git",
|
"url": "https://github.com/sebastianbergmann/complexity.git",
|
||||||
"reference": "c182133e92fc7a8b0a923b5d20f3a9fdfa534818"
|
"reference": "c2deec80b7a2df9556d77cb98e238a8a4780ca32"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/c182133e92fc7a8b0a923b5d20f3a9fdfa534818",
|
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/c2deec80b7a2df9556d77cb98e238a8a4780ca32",
|
||||||
"reference": "c182133e92fc7a8b0a923b5d20f3a9fdfa534818",
|
"reference": "c2deec80b7a2df9556d77cb98e238a8a4780ca32",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3798,7 +3855,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:22:53+00:00"
|
"time": "2021-01-14T08:07:18+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/diff",
|
"name": "sebastian/diff",
|
||||||
|
@ -3806,12 +3863,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||||
"reference": "33f7bf3c1741b2a10e16d5c41c369c402b933e4c"
|
"reference": "3768e4448231a9ed88b8b82d14e3c86c60bc24e0"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/33f7bf3c1741b2a10e16d5c41c369c402b933e4c",
|
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3768e4448231a9ed88b8b82d14e3c86c60bc24e0",
|
||||||
"reference": "33f7bf3c1741b2a10e16d5c41c369c402b933e4c",
|
"reference": "3768e4448231a9ed88b8b82d14e3c86c60bc24e0",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3865,7 +3922,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:21:47+00:00"
|
"time": "2021-01-14T08:05:23+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/environment",
|
"name": "sebastian/environment",
|
||||||
|
@ -3873,12 +3930,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/environment.git",
|
"url": "https://github.com/sebastianbergmann/environment.git",
|
||||||
"reference": "b885263b3601b7570ef386a468d6a827c95c8994"
|
"reference": "23c7b3502969bd25c425f74484a99763e48bdeec"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/b885263b3601b7570ef386a468d6a827c95c8994",
|
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/23c7b3502969bd25c425f74484a99763e48bdeec",
|
||||||
"reference": "b885263b3601b7570ef386a468d6a827c95c8994",
|
"reference": "23c7b3502969bd25c425f74484a99763e48bdeec",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3929,7 +3986,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:21:52+00:00"
|
"time": "2021-01-14T08:05:33+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/exporter",
|
"name": "sebastian/exporter",
|
||||||
|
@ -3937,12 +3994,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/exporter.git",
|
"url": "https://github.com/sebastianbergmann/exporter.git",
|
||||||
"reference": "f670c4f17dffab83b44048f6fe6747a7c6097179"
|
"reference": "3e0ddb2289e17efc39cf03cb6a93286d3ac37de9"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/f670c4f17dffab83b44048f6fe6747a7c6097179",
|
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3e0ddb2289e17efc39cf03cb6a93286d3ac37de9",
|
||||||
"reference": "f670c4f17dffab83b44048f6fe6747a7c6097179",
|
"reference": "3e0ddb2289e17efc39cf03cb6a93286d3ac37de9",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -4007,7 +4064,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:21:58+00:00"
|
"time": "2021-01-14T08:05:42+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/global-state",
|
"name": "sebastian/global-state",
|
||||||
|
@ -4015,12 +4072,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/global-state.git",
|
"url": "https://github.com/sebastianbergmann/global-state.git",
|
||||||
"reference": "a74d82a0654a7f685f80016cc3570d7a387f9da0"
|
"reference": "d172b1d21828f3034f064b02b584b6c86399baa1"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a74d82a0654a7f685f80016cc3570d7a387f9da0",
|
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/d172b1d21828f3034f064b02b584b6c86399baa1",
|
||||||
"reference": "a74d82a0654a7f685f80016cc3570d7a387f9da0",
|
"reference": "d172b1d21828f3034f064b02b584b6c86399baa1",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -4072,7 +4129,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:22:03+00:00"
|
"time": "2021-01-14T08:05:52+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/lines-of-code",
|
"name": "sebastian/lines-of-code",
|
||||||
|
@ -4080,12 +4137,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
|
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
|
||||||
"reference": "db62e01f14ea9485d5a52dfb5706061fd0f50425"
|
"reference": "ec5577068ba8a8f56fcfe66239bfbae6c2af6819"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/db62e01f14ea9485d5a52dfb5706061fd0f50425",
|
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/ec5577068ba8a8f56fcfe66239bfbae6c2af6819",
|
||||||
"reference": "db62e01f14ea9485d5a52dfb5706061fd0f50425",
|
"reference": "ec5577068ba8a8f56fcfe66239bfbae6c2af6819",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -4130,7 +4187,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:22:58+00:00"
|
"time": "2021-01-14T08:07:28+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/object-enumerator",
|
"name": "sebastian/object-enumerator",
|
||||||
|
@ -4138,12 +4195,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/object-enumerator.git",
|
"url": "https://github.com/sebastianbergmann/object-enumerator.git",
|
||||||
"reference": "fccb61351e8a3a10ffacfad9544bb2905905b69c"
|
"reference": "9d9fa9141b9dbc5141a930d30c932634ea714bf2"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/fccb61351e8a3a10ffacfad9544bb2905905b69c",
|
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/9d9fa9141b9dbc5141a930d30c932634ea714bf2",
|
||||||
"reference": "fccb61351e8a3a10ffacfad9544bb2905905b69c",
|
"reference": "9d9fa9141b9dbc5141a930d30c932634ea714bf2",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -4188,7 +4245,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:22:09+00:00"
|
"time": "2021-01-14T08:06:01+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/object-reflector",
|
"name": "sebastian/object-reflector",
|
||||||
|
@ -4196,12 +4253,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/object-reflector.git",
|
"url": "https://github.com/sebastianbergmann/object-reflector.git",
|
||||||
"reference": "c0ad4ce74e040797d5f8abfc23ab79fd79b064c3"
|
"reference": "3c2c8cdd6e598e61fe9182663bc5c65152570af0"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/c0ad4ce74e040797d5f8abfc23ab79fd79b064c3",
|
"url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/3c2c8cdd6e598e61fe9182663bc5c65152570af0",
|
||||||
"reference": "c0ad4ce74e040797d5f8abfc23ab79fd79b064c3",
|
"reference": "3c2c8cdd6e598e61fe9182663bc5c65152570af0",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -4244,7 +4301,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:22:14+00:00"
|
"time": "2021-01-14T08:06:12+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/recursion-context",
|
"name": "sebastian/recursion-context",
|
||||||
|
@ -4252,12 +4309,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/recursion-context.git",
|
"url": "https://github.com/sebastianbergmann/recursion-context.git",
|
||||||
"reference": "c5616ce32278e62c77066f72b1fe413a8c958cee"
|
"reference": "f56f4b45cf5b284977639e9c13bcabb8e10e0d95"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/c5616ce32278e62c77066f72b1fe413a8c958cee",
|
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f56f4b45cf5b284977639e9c13bcabb8e10e0d95",
|
||||||
"reference": "c5616ce32278e62c77066f72b1fe413a8c958cee",
|
"reference": "f56f4b45cf5b284977639e9c13bcabb8e10e0d95",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -4308,7 +4365,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:22:36+00:00"
|
"time": "2021-01-14T08:06:50+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/resource-operations",
|
"name": "sebastian/resource-operations",
|
||||||
|
@ -4372,12 +4429,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/type.git",
|
"url": "https://github.com/sebastianbergmann/type.git",
|
||||||
"reference": "655e3b59cc2e508306dba9c3df08b774055548e7"
|
"reference": "d9383363efecc03b461b82922410e470ee4d13d8"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/655e3b59cc2e508306dba9c3df08b774055548e7",
|
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/d9383363efecc03b461b82922410e470ee4d13d8",
|
||||||
"reference": "655e3b59cc2e508306dba9c3df08b774055548e7",
|
"reference": "d9383363efecc03b461b82922410e470ee4d13d8",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -4421,7 +4478,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-02T06:22:42+00:00"
|
"time": "2021-01-14T08:06:59+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/version",
|
"name": "sebastian/version",
|
||||||
|
@ -4521,12 +4578,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/console.git",
|
"url": "https://github.com/symfony/console.git",
|
||||||
"reference": "5ff54ffca91d307dfcb144af4748571eb9346b71"
|
"reference": "356c70659d6b48595f9f275cd7c4de0d5544c49c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/console/zipball/5ff54ffca91d307dfcb144af4748571eb9346b71",
|
"url": "https://api.github.com/repos/symfony/console/zipball/356c70659d6b48595f9f275cd7c4de0d5544c49c",
|
||||||
"reference": "5ff54ffca91d307dfcb144af4748571eb9346b71",
|
"reference": "356c70659d6b48595f9f275cd7c4de0d5544c49c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -4611,7 +4668,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-11T06:08:00+00:00"
|
"time": "2021-01-14T15:43:35+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-ctype",
|
"name": "symfony/polyfill-ctype",
|
||||||
|
@ -5192,12 +5249,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/string.git",
|
"url": "https://github.com/symfony/string.git",
|
||||||
"reference": "7a62495108b3dc7e749b709357ae720fccb5a39b"
|
"reference": "2f833cf54d5fe9646638c50778016a06b6fe1603"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/string/zipball/7a62495108b3dc7e749b709357ae720fccb5a39b",
|
"url": "https://api.github.com/repos/symfony/string/zipball/2f833cf54d5fe9646638c50778016a06b6fe1603",
|
||||||
"reference": "7a62495108b3dc7e749b709357ae720fccb5a39b",
|
"reference": "2f833cf54d5fe9646638c50778016a06b6fe1603",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -5268,7 +5325,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-10T16:38:27+00:00"
|
"time": "2021-01-12T14:28:55+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "theseer/tokenizer",
|
"name": "theseer/tokenizer",
|
||||||
|
@ -5326,12 +5383,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/twigphp/Twig.git",
|
"url": "https://github.com/twigphp/Twig.git",
|
||||||
"reference": "a0e2cc25723f3cdb6bbaf617664c4e228f1e9886"
|
"reference": "1a0162a612658790cb1f7b468c7698a7ee58001a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a0e2cc25723f3cdb6bbaf617664c4e228f1e9886",
|
"url": "https://api.github.com/repos/twigphp/Twig/zipball/1a0162a612658790cb1f7b468c7698a7ee58001a",
|
||||||
"reference": "a0e2cc25723f3cdb6bbaf617664c4e228f1e9886",
|
"reference": "1a0162a612658790cb1f7b468c7698a7ee58001a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -5397,7 +5454,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-05T15:39:16+00:00"
|
"time": "2021-01-14T07:57:35+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "vimeo/psalm",
|
"name": "vimeo/psalm",
|
||||||
|
|
1
docs/references/account/create-jwt.md
Normal file
1
docs/references/account/create-jwt.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout.
|
|
@ -21,6 +21,7 @@ use Appwrite\Utopia\Response\Model\ErrorDev;
|
||||||
use Appwrite\Utopia\Response\Model\Execution;
|
use Appwrite\Utopia\Response\Model\Execution;
|
||||||
use Appwrite\Utopia\Response\Model\File;
|
use Appwrite\Utopia\Response\Model\File;
|
||||||
use Appwrite\Utopia\Response\Model\Func;
|
use Appwrite\Utopia\Response\Model\Func;
|
||||||
|
use Appwrite\Utopia\Response\Model\JWT;
|
||||||
use Appwrite\Utopia\Response\Model\Key;
|
use Appwrite\Utopia\Response\Model\Key;
|
||||||
use Appwrite\Utopia\Response\Model\Language;
|
use Appwrite\Utopia\Response\Model\Language;
|
||||||
use Appwrite\Utopia\Response\Model\User;
|
use Appwrite\Utopia\Response\Model\User;
|
||||||
|
@ -66,7 +67,8 @@ class Response extends SwooleResponse
|
||||||
const MODEL_USER_LIST = 'userList';
|
const MODEL_USER_LIST = 'userList';
|
||||||
const MODEL_SESSION = 'session';
|
const MODEL_SESSION = 'session';
|
||||||
const MODEL_SESSION_LIST = 'sessionList';
|
const MODEL_SESSION_LIST = 'sessionList';
|
||||||
const MODEL_TOKEN = 'token'; // - Missing
|
const MODEL_TOKEN = 'token';
|
||||||
|
const MODEL_JWT = 'jwt';
|
||||||
|
|
||||||
// Storage
|
// Storage
|
||||||
const MODEL_FILE = 'file';
|
const MODEL_FILE = 'file';
|
||||||
|
@ -168,6 +170,7 @@ class Response extends SwooleResponse
|
||||||
->setModel(new User())
|
->setModel(new User())
|
||||||
->setModel(new Session())
|
->setModel(new Session())
|
||||||
->setModel(new Token())
|
->setModel(new Token())
|
||||||
|
->setModel(new JWT())
|
||||||
->setModel(new Locale())
|
->setModel(new Locale())
|
||||||
->setModel(new File())
|
->setModel(new File())
|
||||||
->setModel(new Team())
|
->setModel(new Team())
|
||||||
|
|
40
src/Appwrite/Utopia/Response/Model/JWT.php
Normal file
40
src/Appwrite/Utopia/Response/Model/JWT.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Appwrite\Utopia\Response\Model;
|
||||||
|
|
||||||
|
use Appwrite\Utopia\Response;
|
||||||
|
use Appwrite\Utopia\Response\Model;
|
||||||
|
|
||||||
|
class JWT extends Model
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->addRule('jwt', [
|
||||||
|
'type' => self::TYPE_STRING,
|
||||||
|
'description' => 'JWT encoded string.',
|
||||||
|
'example' => 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
|
||||||
|
])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Name
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getName():string
|
||||||
|
{
|
||||||
|
return 'JWT';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Collection
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getType():string
|
||||||
|
{
|
||||||
|
return Response::MODEL_JWT;
|
||||||
|
}
|
||||||
|
}
|
|
@ -128,4 +128,102 @@ class AccountCustomClientTest extends Scope
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCreateJWT():array
|
||||||
|
{
|
||||||
|
$email = uniqid().'user@localhost.test';
|
||||||
|
$password = 'password';
|
||||||
|
$name = 'User Name (JWT)';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for SUCCESS
|
||||||
|
*/
|
||||||
|
$response = $this->client->call(Client::METHOD_POST, '/account', array_merge([
|
||||||
|
'origin' => 'http://localhost',
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
]), [
|
||||||
|
'email' => $email,
|
||||||
|
'password' => $password,
|
||||||
|
'name' => $name,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$id = $response['body']['$id'];
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 201);
|
||||||
|
|
||||||
|
$response = $this->client->call(Client::METHOD_POST, '/account/sessions', array_merge([
|
||||||
|
'origin' => 'http://localhost',
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
]), [
|
||||||
|
'email' => $email,
|
||||||
|
'password' => $password,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 201);
|
||||||
|
|
||||||
|
$sessionId = $response['body']['$id'];
|
||||||
|
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
|
||||||
|
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||||
|
'origin' => 'http://localhost',
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||||
|
]));
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 200);
|
||||||
|
|
||||||
|
$response = $this->client->call(Client::METHOD_POST, '/account/jwt', array_merge([
|
||||||
|
'origin' => 'http://localhost',
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||||
|
]));
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 201);
|
||||||
|
$this->assertNotEmpty($response['body']['jwt']);
|
||||||
|
$this->assertIsString($response['body']['jwt']);
|
||||||
|
|
||||||
|
$jwt = $response['body']['jwt'];
|
||||||
|
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||||
|
'origin' => 'http://localhost',
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'x-appwrite-jwt' => 'wrong-token',
|
||||||
|
]));
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 401);
|
||||||
|
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||||
|
'origin' => 'http://localhost',
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'x-appwrite-jwt' => $jwt,
|
||||||
|
]));
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 200);
|
||||||
|
|
||||||
|
$response = $this->client->call(Client::METHOD_DELETE, '/account/sessions/'.$sessionId, array_merge([
|
||||||
|
'origin' => 'http://localhost',
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||||
|
]));
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 204);
|
||||||
|
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||||
|
'origin' => 'http://localhost',
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'x-appwrite-jwt' => $jwt,
|
||||||
|
]));
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 401);
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue