dusterio / lumen-passport Goto Github PK
View Code? Open in Web Editor NEWMaking Laravel Passport work with Lumen
License: MIT License
Making Laravel Passport work with Lumen
License: MIT License
There is no support for implicit grants as the PassportServiceProvider is missing the forAuthorization method which sets up the routing for the authorize endpoints (should be called in registerRoutes).
while requesting the access token for password grant type I got the error
URL : http://localhost:8000/oauth/token
Error : Unable to determine authentication model from configuration.
Hi,
Thank you for your work, but I was searching for Lumen 5.3 and Passport and came here.
Why do we need a packages to make passport word with lumen?
Shouldn't this work out-of-the-box?
What are the problems?
Kind regards,
Jeroen
When trying to use midleware auth:api on a route I receive the error
FatalThrowableError in AuthManager.php line 294:
Call to undefined method Illuminate\Auth\RequestGuard::handle()
in AuthManager.php line 294
at AuthManager->__call('handle', array(object(Request), object(Closure), 'api')) in Pipeline.php line 137
at Pipeline->Illuminate\Pipeline{closure}(object(Request))
at call_user_func(object(Closure), object(Request)) in Pipeline.php line 32
at Pipeline->Laravel\Lumen\Routing{closure}(object(Request)) in Pipeline.php line 104
at Pipeline->then(object(Closure)) in RoutesRequests.php line 647
at Application->sendThroughPipeline(array('auth:api'), object(Closure)) in RoutesRequests.php line 400
at Application->dispatch(null) in RoutesRequests.php line 341
at Application->run() in index.php line 28
When I redirect to oauth/authorize I get: Sorry, the page you are looking for could not be found.
In Passport documentation is saying to add
Passport::routes();
in AuthServiceProvider
Because
Remember, the /oauth/authorize route is already defined by the Passport::routes method. You do not need to manually define this route.
How can I make it work? Where do I need to add Passport::routes();? I am using dusterio/lumen-passport
Access token successfully received by issueToken but forUser->middleware(auth) not working....Please help
Hi,
I'm using PHP v 5.6.28 and i get this error when i call oath/token (POST) :
Syntax at line 27 in vendor\dusterio\lumen-passport\src\Http\Controllers\AccessTokenController.php is not supported
$clientId = array_key_exists('client_id', (array) $request->getParsedBody())
? ((array) $request->getParsedBody())['client_id'] : null;
Replace by
$requestBodyArray = ((array) $request->getParsedBody());
$clientId = array_key_exists('client_id', $requestBodyArray) ? $requestBodyArray['client_id'] : null;
and it works.
Do i need a specific PHP configruation or something ? (array casting in ternary condition ?)
Thanks.
Apologies if this is not a 'code' related issue but SO didn't have much information on this so I assumed this would be the best place to ask. I am confused as to how I am supposed to validate the user in the the AuthServiceProvider.php
that lumen ships with so when the oauth endpoints are hit they can access the current user instance.
Your install instructions asks to use add the auth
entry to the RouteMiddleware
and when we use it the following code gets called
if ($this->auth->guard($guard)->guest()) {
return response('Unauthorized.', 401);
}
To my understanding this will always be false because inside AuthServiceProvider.php
the viaRequest
always evaluating to false and never getting the opportunity to auth the requesting user.
Auth::viaRequest('api', function ($request) {
if ($request->input('api_token')) {
return User::where('api_token', $request->input('api_token'))->first();
}
});
Apologies gain if this not so much of a code issue but more my understanding, I have gone over the install instructions over and over and not sure what I am doing wrong. Thank you.
Hi, thanks for your great work. If i want to customize the default response returned by passport (i just want to add more attribute on response), do you think i've to register an after middelware in PassportServiceProvider? I just want to add my default info on responses in my rest api and i've not control of responses returned by passport.
Do you tink it's a good solution?
Hi there,
Thanks for putting this together - I have just spent the morning tinkering and trying to get this working with Lumen. I have got pretty far and thought it might help other if I put down some notes as to what I did in order to get the Password Grant option working.
I had to modify my minimum stability in the Lumen composer file and grab the latest dev branch
along with adding the included PassportServiceProvider I had to add:
$app->register(Laravel\Passport\PassportServiceProvider::class);
$app->withFacades();
$app->withEloquent();
$app->routeMiddleware([
'auth' => App\Http\Middleware\Authenticate::class,
]);
then create a 'config' folder and add an 'auth.php' file with contents shown in the readme
then run the install commands shown in the main Laravel docs
The rest should be fairly straightforward, basically I added the Passport stuff to my User model, created a protected route and tested it with Postman.
$app->group(['middleware' => 'auth:api'], function () use ($app) {
$app->get('/user', function () {
return "fish";
});
});
Couple of gotchas;
for some reason it didn't generate the APP_KEY when it did the install so I had to manually create a random 32 char string
the client_id is the Primary Key in the database and the client_secret is exactly as it is in the database.
I think this maybe in the passport layer, however I am not completely sure.
I have set both the ttl of the token and the fresh to 1, and 2 minutes. Then waited 5 minutes. I can still access the routes. This is a password grant, not that this should matter.
Hello,
i did all what mentioned in the documentation but im getting NotFoundHttpException
when i call /oauth/token in postman
is this how to Registering Routes:
i put this code in AuthServiceProvider file
public function boot() {
Dusterio\LumenPassport\LumenPassport::routes($this->app);
}
im not sure is it right or no
im using lumen5.4 and lumen-passprot 0.2.0
Working with Lumen 5.4, fresh install. I followed all the steps until this part:
'Next, you should call the LumenPassport::routes
method within the boot method of your application.'
I don't understand where I have to call this method, and the oauth routes are not working. I get a 'NotFoundHttpException' exception.
I found this tutorial and there's no mention of this step, I also noticed that the version used is 0.1 and the latest one is 0.2. So I guess you changed something that makes this extra step needed.
What I mean to say is that the documentation should be more specific for those of us who are not that familiar with laravel/lumen.
Could you explain how to use the necessary routes and parameters?
Hi @dusterio
This looks exactly like what I've been looking for. Was kind of surprised when I saw Passport wasn't working with Lumen out of the box - seems like that would be the first stop for it :)
Anyway, I'm going to try out your package with the latest Lumen install on a production environment. We use a multi node setup, as I like to keep things separate and such. Please let me know if you need any help maintaining this project, code wise or anywhere else.
Thanks again!
Hi. I create a clear lumen project, then install you package, configure it, but i have some problem.
grant_type:password client_id:1 client_secret:mxsoiKILaCDuNTX5KRkbmmxBWE629eHiXy9qavvV username:<email> password:<password>
Response like
{ "token_type": "Bearer", "expires_in": 31536000, "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjdkMjkwNjA4OGQ4NzE5N2IyM2VkNzdjNTFjNmNlNDI5ZWI0MGQxZWQyOTU5M2M1ZjllNmYzZDU2MzUyOGUwMGY4OGNmMWI4MDQ0OTQ4NjBkIn0.eyJhdWQiOiIxIiwianRpIjoiN2QyOTA2MDg4ZDg3MTk3YjIzZWQ3N2M1MWM2Y2U0MjllYjQwZDFlZDI5NTkzYzVmOWU2ZjNkNTYzNTI4ZTAwZjg4Y2YxYjgwNDQ5NDg2MGQiLCJpYXQiOjE0ODQ2ODAwOTUsIm5iZiI6MTQ4NDY4MDA5NSwiZXhwIjoxNTE2MjE2MDk1LCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.rc0Je5en_ppir2roA7XJY6feTrDhEA7RbqXT1q6f4Jhkf2lr5VKpDZrCGHbWUFdhXWXJ91qDes0jVChqoZqR7UcRurwW054mX-hqSYzQiuM9hXaQH-eEfdwyx8qzYEJyB5c9i-CNul7VCru-3vEdsZcMuO3doYAiGW0PHSSvDN7b1qz27BS-6_offE0DZICpNkljJ5cvUqWSravhuScxLrAETQ46Ugb8VVfhGIz9oGeW2KJhfddXV2aTwDPWD8QBTAPN4aYcN4hsW4RXtdY2BbWitHfvKBGwpiu9P1Q-iz3lDVH0jys0ekrwXoaqb2GcBbOZVEbco9_9Ori6GMYacMkG_sOA74ZooqmgkWu1OKSUuY0MToi6UUXN7ngrmNK9hle76uNWgORdGX-2euk2nOIkpk1CiI3ARICLLQOV3a4Zo0-6RTNN1TUE56Zs1gGafTyY7XakN0YK2cKfvGAk-sp00f6G2gzQYuenifJqxLHgOLpWqZTpgBesZ1MZ7q-lJBN5tnImP3Mh-CKHN7hpa4w0FE449fRnKreuqQ8btixUbiwIULeIrWfJgViztHk80rxnMSJkyzwMIf5gzhwkiAjc1dx9uhBqruqIgHbJru5tFuY96tUNSDedV1gkBOlFR6nk55Zog0Y00hQD-cNxJ4QBSuHT1yhM8CGh6y9iR-A", "refresh_token": "R/cjRZGpczj7DEs5MKDu3zSom/wANCjsb+MsbL+jM4E13tQ9fE36ibt1GLnJ3nRR6Yc8RTH0NSk1rptIrMJneZmHIy0XqS0A7RBhYYP/bEqizrPwwBGQaTd1N9hPVSfrXla3wRLapbI+PkGzPPindL8kSF0N/FPOS1oJ3Lwrx5At1vxJheye49jsL/AY7bTBj8KDeS0nD7C0zcQzAAzKiO6pUkFckTA1lrWCzGYs/SWfSNcBSLD/mb/gUrDnL+nJ36bx9pvHs9zG0xeBMy7MoIzVR/cCpUoaFnp1u7rlNBlPKPoH9wtRJInd42/lYrI04HrLvaqkrDf3snEgDrkAFQ5w0yCE62Np7IveimzhbJGE4720PKav2L5D1i7VyjvGONkO26ot0i94HpZOjAyHRy4fZW+mM7+nvqbOg++XooYG5Q1ifh4MckhsuUl2a1yjW3LzhmZtLCRDhk3rDAa2wMDhg4uObZuKTTXPc0yGzJ0SWLwIcxjTkyF814JBzdPd7+Ne3QJIjzxlyvzNUEbujtwnagv9fn5gFyIf6kaZiVyw7XYchCG//dopu3244ByeLE4jGAlTDnHC6p9sXrlgs4PdN0E0fO+cQODMnPhcNsHKp+8X6JhhUsWywkAs77ZYK8vp1q5yg2WLOlfytgKuaQgs69vzu7xcoRx9mopJe78=" }
Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjdkMjkwNjA4OGQ4NzE5N2IyM2VkNzdjNTFjNmNlNDI5ZWI0MGQxZWQyOTU5M2M1ZjllNmYzZDU2MzUyOGUwMGY4OGNmMWI4MDQ0OTQ4NjBkIn0.eyJhdWQiOiIxIiwianRpIjoiN2QyOTA2MDg4ZDg3MTk3YjIzZWQ3N2M1MWM2Y2U0MjllYjQwZDFlZDI5NTkzYzVmOWU2ZjNkNTYzNTI4ZTAwZjg4Y2YxYjgwNDQ5NDg2MGQiLCJpYXQiOjE0ODQ2ODAwOTUsIm5iZiI6MTQ4NDY4MDA5NSwiZXhwIjoxNTE2MjE2MDk1LCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.rc0Je5en_ppir2roA7XJY6feTrDhEA7RbqXT1q6f4Jhkf2lr5VKpDZrCGHbWUFdhXWXJ91qDes0jVChqoZqR7UcRurwW054mX-hqSYzQiuM9hXaQH-eEfdwyx8qzYEJyB5c9i-CNul7VCru-3vEdsZcMuO3doYAiGW0PHSSvDN7b1qz27BS-6_offE0DZICpNkljJ5cvUqWSravhuScxLrAETQ46Ugb8VVfhGIz9oGeW2KJhfddXV2aTwDPWD8QBTAPN4aYcN4hsW4RXtdY2BbWitHfvKBGwpiu9P1Q-iz3lDVH0jys0ekrwXoaqb2GcBbOZVEbco9_9Ori6GMYacMkG_sOA74ZooqmgkWu1OKSUuY0MToi6UUXN7ngrmNK9hle76uNWgORdGX-2euk2nOIkpk1CiI3ARICLLQOV3a4Zo0-6RTNN1TUE56Zs1gGafTyY7XakN0YK2cKfvGAk-sp00f6G2gzQYuenifJqxLHgOLpWqZTpgBesZ1MZ7q-lJBN5tnImP3Mh-CKHN7hpa4w0FE449fRnKreuqQ8btixUbiwIULeIrWfJgViztHk80rxnMSJkyzwMIf5gzhwkiAjc1dx9uhBqruqIgHbJru5tFuY96tUNSDedV1gkBOlFR6nk55Zog0Y00hQD-cNxJ4QBSuHT1yhM8CGh6y9iR-A
Looking forward to hearing from you soon!
Best regards,
Artem
Hi @dusterio
i was following steps given by you
i stuck at place where it says i need to use trait in User model, the project on which i am working is already build and this project is using only controllers no model file is used, tables are directly used in controller. Now Please let me know how i can do this step. Second my user table has some different name, is it will affect passport integration.
Thanks
Hi,
I want to add middleware to the routes defined in PassportServiceProvider. I have tried to override the routes in /routes/web.php:
$app->post('/oauth/token', [ 'middleware' => 'reject', 'uses' => '\Dusterio\LumenPassport\Http\Controllers\AccessTokenController@issueToken', ]);
This is throwing a 500 at me without a error message. I am currently clueless about what is going wrong.
I do not know if it is at all possible to add middleware to package defined routes and can't find any good solutions to my problem. Who is able to help me? :)
In \dusterio\lumen-passport\src\Http\Controllers\AccessTokenController@issueToken() r. 26 is written the following:
$clientId = ((array) $request->getParsedBody())['client_id'] ?? null;
Which is introduced in last commit:
256aece
The ??
operator isn't supported in PHP versions lower then PHP 7, since it is introduced in PHP 7.0:
http://php.net/manual/en/migration70.new-features.php
Therefor the package is crashing instantly when calling (for example): POST /oauth/token endpoints
Suggested fix, something in line of:
$clientId = !is_null($request->getParsedBody()) ? $request->getParsedBody()['client_id'] : null;
or increasing 'minimum supported php' to version 7 π
I am getting this without a clue on how to fix it.
It seems like when I call my oauth using get with a token I dont get unauthoized but i get this error instead
SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for integer: "" (SQL: select * from "users" where "users"."id" = limit 1)
I been working on it for hours. trying to find any clue on what is going on.
Hello,
I'm using dusterio/lumen-passport in the version ^ 0.2.0, in Lumen 5.4; Xampp, Apache, Win 10.
I followed the instructions available in the README
My .htaccess is as follows:
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
I have the following route with middlware 'auth':
$app->get('/passport-test', function(){
return true;
})->middleware('auth');
But every time I access it, I get the following error:
Fatal error: Call to undefined method Illuminate\Auth\RequestGuard::handle() in C:\xampp\htdocs\my-app\vendor\illuminate\auth\AuthManager.php on line 294
Am I doing something stupidly wrong?
Hi,
is this library compatible with Lumen 5.4?
Kind regards and keep up the great work!
PS. I came from esbenp's implementation in Lumen 5.0/5.1, via the updated oauth2 implementation from lucadegasperi/oauth2-server-laravel in 5.2 and now via the Laravel Passport implementation with Lumen 5.3
Method LumenPassport::routes needs to be modified for ability to take $callback
argument as in Laravel\Passport::routes.
For example:
Dusterio\LumenPassport\LumenPassport::routes($app, $callback, $options);
This will allow configure only necessary routes.
I need to change Authorization header to my custom Authorization header called X-OAuth-Authorization. can I do that? Because I want to use Authorization header for my middleware authentications. What should I do?
I follow all the steps and can't access /oauth/token to get the token, is it supported for Lumen 5.4 or i should using Lumen 5.3 ?
I edit the config/auth.php and change the default into 'api' but i still can't access the api routes, the routes still connected with web.php routes. what happened?
Nginx environment, access "oauth/token", return to "unsupported_grant_type"; Apache environment, normal work
I noticed the original Laravel Passport package supports prefixing the routes - however, in the lumen-passport package it looks like the routes are hardcoded into PassportServiceProvider. More than happy to provide a PR but wanted to get an idea of implementation?
Did you want it to read from a config file or a static function call.
have this in my composer.json
"require": {
"php": ">=5.6.4",
"laravel/lumen-framework": "5.4.*",
"vlucas/phpdotenv": "~2.2",
"dusterio/lumen-passport": "^0.1.9"
},
there're few methods missing in LumenPassport.php and RouteRegistrar.php file missing
I've used following command to get this in
$ composer require dusterio/lumen-passport
I'm using lumen 5.4 and I'm having a hard time making an initial configuration, I have no idea where the 'config/auth.php' file is.
Is it because of the laravel version?
Hi,
First of all, congratiolations for your package, it is really helpful !
I see that in the "Dusterio\LumenPassport\Http\Controllers\AccessTokenController" class you have the revokeOtherAccessTokens method, which calls the passport standard method revokeOtherAccessTokens.
However, the passport standard method "revokeOtherAccessTokens" is now deprecated and the source code does nothing more.. I couldn't find a quick replace for this method, but I saw this in the comments:
/** * Revoke all of the access tokens for a given user and client. * * @deprecated since 1.0. Listen to Passport events on token creation instead. * * @param mixed $clientId * @param mixed $userId * @param bool $prune * @return void */ public function revokeOtherAccessTokens($clientId, $userId, $except = null, $prune = false) { // }
Could you please help me to get this to work again ?
Thanks !
Hi, So I used
php artisan passport:client
to generate access for a user
and then using postman I passed data:
grant_type:password
client_secret:wE9VJSLpXIJ4b5B4eryx9RtjSXWmdrWqUQ4VIQP4
client_id:4
username:[email protected]
password:hello21
scope:basic
However response I get is:
{
"error": "invalid_client",
"message": "Client authentication failed"
}
How can that be solved?
it seems that apache discards the Authorization header if it is not a base64 encoded user/pass combo. See there https://github.com/tymondesigns/jwt-auth/wiki/Authentication.
Today i've faced this iusse. Maybe this saves a little bit of time to someone else. Just put in .htaccess, or apache config the following lines:
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
Hi there!
First, thanks guys! This project saved a lot of my time. <3
In readme have a console command for purging expired tokens and I schedulle in my server, but i noticed that this command don't deleted the expired tokens of client_grant, which don't have refresh_token. So I made a contribution for make this too! It's in pull 45
That's all!
When you upgrade to the 0.2.0 version, the '/oauth/token' path returns' NotFoundHttpException in RoutesRequests.php line 594: 'οΌand it is normal to switch to the 0.1.9 version
Will you be adding the ability to define which scopes can be used by a client? Particularly useful for client credentials grant.
Hi,
Laravel passport also allows to set the refresh token lifetime via refreshTokensExpireIn
.
Is there any way to do this in this package as well or am I missing sth.?
Cheers!
Have an issue with package using.
Sending to oauth/token
POST request with next params (js):
const credentials = { grant_type: "password", client_id: 2, client_secret: "my_secret_client", scope: "*", username: "[email protected]", password: "password" };
My DB users
table:
http://prntscr.com/ge1xe8
users
table values:
http://prntscr.com/ge1xv7
Seeded like this:
http://prntscr.com/ge1y59
But when I try to take a token from API, it response error The user credentials were incorrect.
How I can solve this problem? Thanks!
Does your update takes custom TTL of tokens into account?
I see the following in the issueToken() method (in AccessTokenController):
$this->server->enableGrantType(
$this->makePasswordGrant(), LumenPassport::tokensExpireIn(null, $clientId)
);
I, am using in bootstrap/app.php:
\Laravel\Passport\Passport::tokensExpireIn(\Carbon\Carbon::now()->addSeconds(env('API_ACCESS_TOKEN_TTL', 600)));
\Laravel\Passport\Passport::refreshTokensExpireIn(\Carbon\Carbon::now()->addDays(30));
But my response is:
"body": {
"refresh_token": "isQRZ82dGu61x.....",
"access_token": "eyJ0eXAiOiJKV1Q.....",
"token_type": "Bearer",
"expires_in": 3155673600
},
"expires_in": 3155673600
is not 600, what is going wrong?
.env var:
API_ACCESS_TOKEN_TTL=600
update
refreshing token still works with custom TTL (expires_in)
Hi,
I followed all the steps but the routes are not mounted there in lumen route folder?
I didn't understand this line? I think I am doing something wrong after the passport:install command.
"Adding this service provider, will mount the following routes:"
What's the meaning of this line?
i will php migrate Migrate and install Laravel Passport not work
Passport comes originally with three Vue components for a default frontend.
=> https://laravel.com/docs/5.3/passport#frontend-quickstart
Is there a simple way to integrate these components for Lumen?
Hi @dusterio. I'm a newbie to Lumen and Laravel, but I'm really liking what I'm seeing. Really love your package.
What I'm trying to do is when a user requesting Password grant specifies the scope as * check all available scopes and assign only those matching some criteria from the client to the token. So let's say I have an array of roles in my User model that map to scopes, and a user has 2 of 3 of them, when requesting * the resulting token would only have the 2 that the user is allowed.
I think if I can do this then I can easily use \Laravel\Passport\Http\Middleware\CheckForAnyScope as my guard for most of my routes.
Thanks again!
@dusterio Can you provide us with your plans of maintaining this package? Are there features being developed or bugs/functionalities that need to be checked? etc. etc.
Just curious what the future holds for this package ;)
Hi, I have followed the documentation and installed the package + configured it. However when I getto one of the routes I get that I am not authorised. How do I pass a token in the url in order to be authorised?
@dusterio maybe in the readme you should say that User model should implements:
use Laravel\Passport\HasApiTokens;
use Illuminate\Auth\Authenticatable;
class User extends Model
{
use Authenticatable, HasApiTokens;
For example in the laraverl docs they say that users model should do this:
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
but using this class we get for example:
Fatal error: Class 'Illuminate\Foundation\Auth\User' not found in D:\XamppAmbient\htdocs\RestApi\app\User.php on line
not using Authenticatable trait we get:
lumen.ERROR: exception 'BadMethodCallException' with message 'Call to undefined method Illuminate\Database\Query\Builder::getAuthIdentifier()' in D:\XamppAmbient\htdocs\RestApi\vendor\illuminate\database\Query\Builder.php:2448
what do you think?
{
"error": "unsupported_grant_type",
"message": "The authorization grant type is not supported by the authorization server.",
"hint": "Check the grant_type
parameter"
}
I get this error when I put my /oauth/token route using postman
Any solution?
Cheers!
im facing issues with passport,
i implemented it and it generating the token,
when i call oauth/token i get in the response:
{
"token_type": "Bearer",
"expires_in": "31536000",
"access_token": "eyJ0eXAiOiJKV1QiLCJhbG..",
"refresh_token": "def502004a2bce74be3d2..",
}
im using postman for testing.
lumen 5.4 and passport 0.2.4
when I called /oauth/token/refresh or /oauth/tokens then its throw
InvalidArgumentException in AuthManager.php line 99:
Auth guard driver [api] is not defined.
I am using the function "LumenPassport :: tokensExpireIn (Carbon :: now () -> addDays (2), 2);" With the second client id parameter. The problem is that I always get the default value (one year).
I have tested "LumenPassport :: tokensExpireIn (Carbon :: now (-> addDays (2))"; Without the second client id parameter and working properly.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.