Git Product home page Git Product logo

jwt's Introduction

Koa middleware for validating JSON Web Tokens.

node version npm download npm stats test status coverage license

Table of Contents

Introduction

This module lets you authenticate HTTP requests using JSON Web Tokens in your Koa (node.js) applications.

See this article for a good introduction.

  • If you are using koa version 2+, and you have a version of node < 7.6, install koa-jwt@2.
  • koa-jwt version 3+ on the master branch uses async / await and hence requires node >= 7.6.
  • If you are using koa version 1, you need to install koa-jwt@1 from npm. This is the code on the koa-v1 branch.

Install

npm install koa-jwt

Usage

The JWT authentication middleware authenticates callers using a JWT token. If the token is valid, ctx.state.user (by default) will be set with the JSON object decoded to be used by later middleware for authorization and access control.

Retrieving the token

The token is normally provided in a HTTP header (Authorization), but it can also be provided in a cookie by setting the opts.cookie option to the name of the cookie that contains the token. Custom token retrieval can also be done through the opts.getToken option. The provided function should match the following interface:

/**
 * Your custom token resolver
 * @this The ctx object passed to the middleware
 *
 * @param  {Object}      opts The middleware's options
 * @return {String|null}      The resolved token or null if not found
 */

opts, the middleware's options:

  • getToken
  • secret
  • key
  • isRevoked
  • passthrough
  • cookie
  • audience
  • issuer
  • debug

The resolution order for the token is the following. The first non-empty token resolved will be the one that is verified.

  • opts.getToken function.
  • check the cookies (if opts.cookie is set).
  • check the Authorization header for a bearer token.

Passing the secret

One can provide a single secret, or array of secrets in opts.secret. An alternative is to have an earlier middleware set ctx.state.secret, typically per request. If this property exists, it will be used instead of opts.secret.

Checking if the token is revoked

You can provide a async function to jwt for it check the token is revoked. Only you set the function in opts.isRevoked. The provided function should match the following interface:

/**
 * Your custom isRevoked resolver
 *
 * @param  {object}   ctx            The ctx object passed to the middleware
 * @param  {object}   decodedToken   Content of the token
 * @param  {object}   token          token The token
 * @return {Promise}                 If the token is not revoked, the promise must resolve with false, otherwise (the promise resolve with true or error) the token is revoked
 */

Example

var Koa = require('koa');
var jwt = require('koa-jwt');

var app = new Koa();

// Custom 401 handling if you don't want to expose koa-jwt errors to users
app.use(function(ctx, next){
  return next().catch((err) => {
    if (401 == err.status) {
      ctx.status = 401;
      ctx.body = 'Protected resource, use Authorization header to get access\n';
    } else {
      throw err;
    }
  });
});

// Unprotected middleware
app.use(function(ctx, next){
  if (ctx.url.match(/^\/public/)) {
    ctx.body = 'unprotected\n';
  } else {
    return next();
  }
});

// Middleware below this line is only reached if JWT token is valid
app.use(jwt({ secret: 'shared-secret' }));

// Protected middleware
app.use(function(ctx){
  if (ctx.url.match(/^\/api/)) {
    ctx.body = 'protected\n';
  }
});

app.listen(3000);

Alternatively you can conditionally run the jwt middleware under certain conditions:

var Koa = require('koa');
var jwt = require('koa-jwt');

var app = new Koa();

// Middleware below this line is only reached if JWT token is valid
// unless the URL starts with '/public'
app.use(jwt({ secret: 'shared-secret' }).unless({ path: [/^\/public/] }));

// Unprotected middleware
app.use(function(ctx, next){
  if (ctx.url.match(/^\/public/)) {
    ctx.body = 'unprotected\n';
  } else {
    return next();
  }
});

// Protected middleware
app.use(function(ctx){
  if (ctx.url.match(/^\/api/)) {
    ctx.body = 'protected\n';
  }
});

app.listen(3000);

For more information on unless exceptions, check koa-unless.

You can also add the passthrough option to always yield next, even if no valid Authorization header was found:

app.use(jwt({ secret: 'shared-secret', passthrough: true }));

This lets downstream middleware make decisions based on whether ctx.state.user is set. You can still handle errors using ctx.state.jwtOriginalError.

If you prefer to use another ctx key for the decoded data, just pass in key, like so:

app.use(jwt({ secret: 'shared-secret', key: 'jwtdata' }));

This makes the decoded data available as ctx.state.jwtdata.

You can specify audience and/or issuer as well:

app.use(jwt({ secret:   'shared-secret',
              audience: 'http://myapi/protected',
              issuer:   'http://issuer' }));

You can specify an array of secrets.

The token will be considered valid if it validates successfully against any of the supplied secrets. This allows for rolling shared secrets, for example:

app.use(jwt({ secret: ['old-shared-secret', 'new-shared-secret'] }));

Token Verification Exceptions

If the JWT has an expiration (exp), it will be checked.

All error codes for token verification can be found at: https://github.com/auth0/node-jsonwebtoken#errors--codes.

Notifying a client of error codes (e.g token expiration) can be achieved by sending the err.originalError.message error code to the client. If passthrough is enabled use ctx.state.jwtOriginalError.

// Custom 401 handling (first middleware)
app.use(function (ctx, next) {
  return next().catch((err) => {
    if (err.status === 401) {
      ctx.status = 401;
      ctx.body = {
        error: err.originalError ? err.originalError.message : err.message
      };
    } else {
      throw err;
    }
  });
});

If the tokenKey option is present, and a valid token is found, the original raw token is made available to subsequent middleware as ctx.state[opts.tokenKey].

This module also support tokens signed with public/private key pairs. Instead of a secret, you can specify a Buffer with the public key:

var publicKey = fs.readFileSync('/path/to/public.pub');
app.use(jwt({ secret: publicKey }));

If the secret option is a function, this function is called for each JWT received in order to determine which secret is used to verify the JWT.

The signature of this function should be (header, payload) => [Promise(secret)], where header is the token header and payload is the token payload. For instance to support JWKS token header should contain alg and kid: algorithm and key id fields respectively.

This option can be used to support JWKS (JSON Web Key Set) providers by using node-jwks-rsa. For example:

const { koaJwtSecret } = require('jwks-rsa');

app.use(jwt({ 
  secret: koaJwtSecret({
    jwksUri: 'https://sandrino.auth0.com/.well-known/jwks.json',
    cache: true,
    cacheMaxEntries: 5,
    cacheMaxAge: ms('10h') 
  }),
  audience: 'http://myapi/protected',
  issuer: 'http://issuer' 
}));

Related Modules

Note that koa-jwt no longer exports the sign, verify and decode functions from jsonwebtoken in the koa-v2 branch.

Tests

npm install
npm test

Authors/Maintainers

Credits

The initial code was largely based on express-jwt.

Contributors

License

MIT

jwt's People

Contributors

3imed-jaberi avatar buuug7 avatar cesarandreu avatar clintmod avatar dependabot[bot] avatar dunnock avatar eterna2 avatar ferguscan avatar getuliojr avatar hassan-jahan avatar jackong avatar madarche avatar michaelwestphal avatar nfantone avatar niftylettuce avatar ontouchstart avatar perlover avatar raman-nbg avatar rrequero avatar scttcper avatar sdd avatar snyk-bot avatar soygul avatar stiang avatar syaning avatar tejasmanohar avatar winfinit avatar wuppious avatar zce avatar zimme avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jwt's Issues

TypeScript typings (and documentation) wrong for getToken function

The typings for Options indicate that getToken's first parameter should be the options for the middleware. The documentation says that getToken's first parameter should be the options for the middleware and that "this" inside the function should be the Koa context.

In the code itself, the first parameter to getOptions is (very sensibly) the Koa context, while the options are the second parameter.

To get around this, I used a hack like this:

// "get" below is lodash's get method.
const koaJwtOptions = {
    secret: config.secret,
    getToken(opts: any) {   // opts is ACTUALLY Koa.Context
        const jwt = get(opts, "query._j") || get(opts, "query.jwt")
        return jwt;
    }
  }

Missing callback function parameter

Is it normal that the JWT.verify function is called without the callback function parameter?

yield JWT.verify(token, secret, opts)

Yet, in jsonwebtoken module, it is :

JWT.verify = function(jwtString, secretOrPublicKey, options, callback)

jsonwebtoken module tests if the third parameter is a function or not, and if so, take the third parameter as the callback function but what if I want both opts and callback?

**WANTED**: pass token.payload to secret function

The current implementation allow me to pass different secret to verify the token using ctx.state.secret
its also possible to get a function to make it done.

In current implementation of secret function is called like that return provider(decoded.header);
I want to be able decide on my secret based on payload

Proposed Solution:
return provider(decoded.header, decoded.payload);
it's will not affect the current existing code and look like safe to add it

update
actually have pending pull request to https://github.com/koajs/jwt/pulls

I get `.sign is not defined`

I get sign is not defined error when doing (v2)

npm install koa-jwt@v2

const jwt = require('koa-jwt');
jwt.sign({ role: 'user' }, 'A very secret key')

Using node-jsonwebtoken error message ?

Suggestion for using node-jsonwebtoken module error message

see https://github.com/auth0/node-jsonwebtoken errors:
TokenExpiredError and JsonWebTokenError

change file index.js line 51

 if (!passthrough) {
                const msg = debug ? e.message : 'Authentication Error';
                ctx.throw(401, msg);
            }

change to

 if (!passthrough) {
                const msg = debug ? e.message : e.message || 'Authentication Error';
                ctx.throw(401, msg {name : e.name || 'UnauthorizedError'});
            }

installation infomation in the readme.

there is my question:

I want to user koa-jwt to help me to build the verification system with [email protected], so I am installed link this:

npm install koa-jwt --save

And I run the example like readme, but it doesn't work. I get confused. Later, I realize that is the compatibility between [email protected] and [email protected].

npm install koa-jwt@1 --save

It worked! :)

So, I thought write the installation information in the readme will be good.

tokenResolvers.find can't work

under some special circumstances, function jwt can work but tokenResolvers.find can't work, so token is undefind, it happend after I download a file form server, when I use

tokenResolvers.forEach(resolver => {
      if (resolver(ctx, opts)) {
        token = resolver(ctx, opts);
      }
});

instead of

tokenResolvers.find(resolver => token = resolver(ctx, opts));

it can works well after I download file

Fails NSP check

Would love to use this library, but my organization will not allow it because it fails the NSP check.

nsp check --reporter checkstyle

Prototype pollution attack 
Name: hoek
CVSS: 4 (Medium) 
Installed: 2.16.3
Vulnerable: <= 4.2.0 || >= 5.0.0 < 5.0.3  
Patched: > 4.2.0 < 5.0.0 || >= 5.0.3 
Path: XXXXXXXXXX > > [email protected] > [email protected] >   [email protected] > [email protected]    
More Info: https://nodesecurity.io/advisories/566   

Looks like upgrading jsonwebtoken to 8+ should resolve this: https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v7-to-v8

After upgrading to koa-jwt 2 I get ' Error: non-error thrown: 401'

I'm using: "koa": "^2.0.0-alpha.3", and "koa-jwt": "^2.0.1" like so:

router.post('/api/userupdate', jwt({secret: config.database.jwtSecret}), 
  function* (next){
    this.body = this.request.body    
    console.log(this.body)
    yield this.body
  }
)
app.use(router.routes()).use(router.allowedMethods())

But I'm getting the not auth error message in subject. The jwt token is send with the request headers on the 'Authorization' . What's wrong with my implementation?

Question

Hi, is possible to wrap this middleware or any way to add dynamic aud?

pseudocode example:

const checkJWT = async (ctx, next) => {
  return await koajwt({secret: 'secret-string', audience : ctx.get('x-custom-header')});
}

app.use(checkJWT());

thanks in advance.

Pass token on query string / allow passing custom getToken function

It would be nice to allow passing the token on the query string (?token=....) instead of having to passing it as a request header. express-jwt permits this by allowing you to pass a custom getToken function like so:

app.use(jwt({
  secret: 'hello world !',
  credentialsRequired: false,
  getToken: function fromHeaderOrQuerystring (req) {
    if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
        return req.headers.authorization.split(' ')[1];
    } else if (req.query && req.query.token) {
      return req.query.token;
    }
    return null;
  }
}));

Sign is missing in 2.1.0

Why is sign function missing in 2.1.0? Will it be added in the future? For now should i use one from jsonwebtoken ?

koa-jwt with koa-router

I'm trying to implement this with koa-router and I can't seem to get it work, I'm somewhat new to koa so I'm sure I'm just misunderstanding something in the koa architecture, but is there a way to get these two modules to play nice?

jsonwebtoken 5.0.0

Is this getting updated soon? getting npm deprecated warning

npm WARN deprecated [email protected]: Critical vulnerability fix in v5.0.0. See https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/

koa@2, ctx.state.user gets undefined value

I'm using koa-jwt for koa@2, so I installed koa-jwt by running npm i --save koa-jwt@koa2.
Authorizing token works, but when I call ctx.state.user, it returns undefined. I did some debugging and it turns out that this line is executed after route handler function is called. Any idea how to fix this?

Unable to determine when tokens have expired

I understand we can add a debug flag now to the options like this as suggested in #98 but it seems like it would be better to have access to the original error object.

ctx.throw(401, msg);

Instead of the above line of code can we add an originalError instead and assign it the original error from jsonwebtoken (e.g. TokenExpiredError).
ctx.throw(401, msg, {originalError: e});

Where originalError.message would be something like "jwt expired" that end clients could key on to know to refresh the token.

Then we could do something like this to notify client apps about the problems that they might need to handle (e.g. token expiration).

// Custom 401 handling
app.use(function (ctx, next) {
  return next().catch((err) => {
    if (err.status === 401) {
      ctx.status = 401;
      ctx.body = {
        error: err.originalError ? err.originalError.message : err.message;
      };
    } else {
      throw err;
    }
  });
});

[Warning] koa deprecated Support for generators will be removed in v3

Hi I'm getting the following warning

koa deprecated Support for generators will be removed in v3. See the documentation for examples of how to convert old middleware https://github.com/koajs/koa/blob/master/docs/migration.md server/index.js:42:5

my example code:

...
app.use(jwt({ secret: Token.secret }).unless({ path: [
  /^\/api\/authentication/, 
  /^\/api\/signup.*/,
]}));
...

I whish to know howto remove the warning, Docs says that I should to use async/await version of the middleware, however I didn't found howto make that in the Readme.

Any help will be appreciated.
Best Regards.

Alive?

This project is now two major versions behind current jsonwebtoken (7.1.6 at the moment). Any plans on catching up?

NPM needs updating

Hi! I installed koa-jwt via npm, and was running into issues trying to use the changes outlined in this PR: #39

I noticed it was included in the 1.2.0 tag here on github, but the latest install (1.2.0) from npm has an older version which does not include these changes.
I see it was stated NPM was updated (#39 (comment)), but it doesn't seem to be that way heh :)

BC: if key is set to token, the new tokenKey default will overwrite it

I realize this is very nit-picky.

Commit 9cf6a15 adds a tokenKey that writes the raw token to the key specified. This'll break backwards compatibility if the "key" preference is set to 'token' like this:

const jwt = require('koa-jwt');
jwt({ key: 'token'});

In that case, the value at token will be the user variable in versions <=1.2.0 but the raw string token in 1.3.0 >=.

Remove Bluebird

Although #58 shows as merged, the changes were not incorporated due to the ongoing discussion, and were reverted by a subsequent commit. Unfortunately merging #72 caused GitHub to mark #58 as merged and will not let me re-open that PR (sorry @scttcper!).

Incorrect describe in section `Checking if the token is revoked` of readme

In the interface comment:

If the token is not revoked, the promise must resolve with false, otherwise (the promise resolve with false or error) the token is revoked

should be

If the token is not revoked, the promise must resolve with false, otherwise (the promise resolve with true or error) the token is revoked

It will be misleading

Breaking change in minor version

Switching to ctx.state.user in a minor version update breaks all of existing code that depends on 0.x branch! It's highly inconvenient and minor version change should be reverted to working state while the changes should be applied to 1.x branch. Koa will probably follow the same pattern as they are holding back a new release for some time.

Alg field should be checked by the server.

Hello,

Correct me if I'm wrong but I think that the Alg field is not an option that can be fixed in this jwt module, alg is known to the server-side and should be checked before analyzing the token !

Auth0 issued a statement saying that not fixing the alg field can introduce a security break :

tl;dr : The fact that the header is not crypted and checked means that anyone can simply fix the alg field he wants : none, SHA512, SHA256 etc. a public key can become a private key etc.

jsonwebtoken, the library powering koa jwt offers this feature, should be simple to make a fix :). Waiting for your inputs before doing any fix.

Update jsonwebtoken dependency

The version this module uses is 5.0.5, while the newest is 5.4.0. There is no reason why this module uses a tilde ~ dependency on jsonwebtoken and not a caret ^ dependency. The exported sign/verify functions miss features the newest jsonwebtoken version has. I have to use option expiresInSeconds which is already deprecated in the newest version.

Type definitions don't support JWK

Type definitions in types/index.d.ts don't support the documented configuration using jwks. Typical configuration looks like this:

import * as jwt from 'koa-jwt'
import * as jwks from 'jwks-rsa'

export default jwt({
  secret: jwks({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: "https://foo.com/.well-known/jwks.json"
  }),
  audience: 'https://foo/',
  issuer: "https://foo.com/",
  algorithms: ['RS256']
})

And this code works in js. It's easy enough to have a workaround with the missing audience issuer and algorithms keys but the secret is defined as sting | Buffer

I'll happily submit a PR for the missing keys; but I'm not quite sure what to do with the secret.

Strange behavior middleware

I always thought that if my token isn't valid I can't get next middleware. Is it correct logic?!
But I'm using your middleware and it isn't working how I thought.

return JWT.verifyAsync(token, secret, opts)
      .then(isRevoked(ctx, token))
      .then(user => {
        ctx.state = ctx.state || {};
        ctx.state[opts.key] = user;
        if (opts.tokenKey) {
          ctx.state[opts.tokenKey] = token;
        }
      })
      .catch(e => {
        if (!opts.passthrough) {
          const msg = 'Invalid token' + (opts.debug ? ' - ' + e.message : '') + '\n';
          ctx.throw(401, msg);
        }
      })
      .then(next);

petkaantonov/bluebird#476
Do you know about it?

Validating token using audience, issuer never fails

Validating claims within audience and issuer fields never fail.

Validating

app.use(jwt( { secret: 'shared-secret', audience: 'http://myapi/protected', issuer: 'http://issuer' }));

against a token containing

{ ... audience: 'something-nice', issuer: 'bogus' ... }

does not fail.

What exactly does state.user get set to?

The docs say state.user gets "set". But what does it get set to? I expected that this module saves the payload of the JWT in state.token or something like that.

Make authentication errors available when using passthrough

Some very useful debugging information is available when JWT authentication fails. However, if passthrough is being used, this information is made unavailable. As a result, it cannot even be logged.

I'd love to see that info be made available somehow.

Verify kid matches issuer

We pass a function to secret so that it can verify the JWT based on the kid in the header. The kid is something like <issuer>/<key-id>. We would also like to verify that the issuer in the token is correct to avoid that a compromised private key is used to impersonate another service e.g. doing something like token.header.kid.startsWith(token.payload.iss + '/'). Unfortunately we cannot do that ourselves at the moment as only the payload is returned by jsonwebtoken.verify which is used by this lib, and only the header is passed to the secret provider.

I'm proposing that the provider is called with both the header and the payload as a second argument to avoid a breaking change. If you're OK with that, I'm happy to send a PR for that.

koa-jwt SyntaxError: Unexpected token function

error when use node --debug bin/run to debug on VSC
try node version 7.0-7.9 all failed

`
Debugging with legacy protocol because a runtime executable is set.
npm run-script start

[email protected] start /Users/xxx/Desktop/pro
nodemon --debug bin/run
[nodemon] 1.11.0
[nodemon] to restart at any time, enter rs
[nodemon] watching: .
[nodemon] starting node --debug bin/run
Debugger listening on 127.0.0.1:5858
/Users/xxx/Desktop/pro/node_modules/koa-jwt/lib/index.js:17
const middleware = async function jwt(ctx, next) {
^^^^^^^^
SyntaxError: Unexpected token function
at Object.exports.runInThisContext (vm.js:78:16)
at Module._compile (module.js:543:28)
at Module._extensions..js (module.js:580:10)
at Object.require.extensions.(anonymous function) [as .js] (/Users/xxx/Desktop/pro/node_modules/babel-register/lib/node.js:152:7)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.require (module.js:498:17)
at require (internal/module.js:20:19)
at Object. (/Users/nathanmb/Desktop/luim/app.js:16:13)
at Module._compile (module.js:571:32)
at loader (/Users/xxx/Desktop/pro/node_modules/babel-register/lib/node.js:144:5)
at Object.require.extensions.(anonymous function) [as .js] (/Users/xxx/Desktop/pro/node_modules/babel-register/lib/node.js:154:7)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
[nodemon] app crashed - waiting for file changes before starting...
`

Support an option to validate the decoded jwt

Once I have verified the jwt, I want to check if a certain field is set properly.

For eg:
If I have set a role field in jwt, on admin routes I want to only allow to pass if the role is set to admin.

role => jwt({
  secret: confirm.secret,
  validate: decoded => decoded.role === role
})

npm's koa-kwt@latest is v2 branch

I've just been reading Koa's v2 roadmap, and spotted this:

All of the current stable versions of middleware should be targeting koa v1. If it doesn't, let us know and we'll fix it.

Middleware may have an "alpha" version of the koa v2 version. These should NOT be marked as stable. If they do not exist, let us know and we'll create an alpha version so you can try it with koa v2. Better yet, make a PR!

Unfortunately my recent npm publish of v2 had dist-tag latest, so if someone starts a new empty project and runs npm install koa koa-jwt, they will end up with koa v1.2.4 and koa-jwt v2.2.1 😢 Consider this minimal example script in that environment:

const koa = require('koa');
const jwt = require('koa-jwt');

const app = koa();
app.use(jwt({ secret: 'shhh' }));
app.listen(3000);

This dies with AssertionError: app.use() requires a generator function. Sorry if anyone has been affected, it's my fault. I'll republish the 1.x branch ASAP with the latest tag to correct this.

For the v2 branch we should probably do what Koa does. This means that an npm publish on v2 will have the right tag automatically.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.