Coder Social home page Coder Social logo

laardee / serverless-authentication-boilerplate Goto Github PK

View Code? Open in Web Editor NEW
569.0 31.0 71.0 333 KB

Generic authentication boilerplate for Serverless framework

Home Page: http://laardee.github.io/serverless-authentication-gh-pages

License: MIT License

JavaScript 100.00%
serverless serverless-framework boilerplate oauth-provider oauth2

serverless-authentication-boilerplate's Introduction

Serverless Authentication

serverless

Build Status

This project is aimed to be a generic authentication boilerplate for the Serverless framework.

This boilerplate is compatible with the Serverless v.1.30.3+, to install Serverless framework run npm install -g serverless.

Web app demo that uses this boilerplate: http://laardee.github.io/serverless-authentication-gh-pages

If you are using Serverless framework v.0.5, see branch https://github.com/laardee/serverless-authentication-boilerplate/tree/serverless-0.5

Installation

The installation will create one DynamoDB table for OAuth state and refresh tokens.

  1. Run serverless install --url https://github.com/laardee/serverless-authentication-boilerplate, clone or download the repository
  2. Change directory to authentication and rename example.env.yml in authentication to env.yml and set environmental variables.
  3. Run npm install.
  4. Run serverless deploy on the authentication folder to deploy authentication service to AWS.
  5. (optional) Change directory to ../test-token and run serverless deploy to deploy test-token service.

If you wish to change the cache db name, change CACHE_DB_NAME in .env file and TableName in serverless.yml in Dynamo resource.

Set up Authentication Provider Application Settings

The redirect URI that needs to be defined in OAuth provider's application settings is the callback endpoint of the API. For example, if you use facebook login, the redirect URI is https://API-ID.execute-api.us-east-1.amazonaws.com/dev/authentication/callback/facebook and for google https://API-ID.execute-api.us-east-1.amazonaws.com/dev/authentication/callback/google.

If you have a domain that you can use, the configuration is explained in the custom domain name section.

Services

In this example project authentication and authorization services are separated from the content API (test-token).

Authentication

Authentication service and authorization function for content API. These can also be separated if needed.

Functions:

  • authentication/signin
    • endpoint: /authentication/signin/{provider}, redirects to oauth provider login page
    • handler: signin function creates redirect url to oauth provider and saves state to DynamoDB
  • authentication/callback
    • endpoint: /authentication/callback/{provider}, redirects back to client webapp with token url parameter
    • handler: function is called by oauth provider with code and state parameters and it creates authorization and refresh tokens
  • authentication/refresh
    • endpoint: /authentication/refresh/{refresh_token}, returns new authentication token and refresh token
    • handler: function revokes refresh token
  • authentication/authorize
    • endpoint: no endpoint
    • handler: is used by Api Gateway custom authorizer

Test-token

Simulates content API.

Functions:

  • test-token/test-token
    • endpoint: /test-token
    • handler: test-token function can be used to test custom authorizer, it returns principalId of custom authorizer policy. It is mapped as the username in request template.

Environmental Variables

Open authentication/env.yml, fill in what you use and other ones can be deleted.

dev:
# General
  SERVICE: ${self:service}
  STAGE: ${opt:stage, self:provider.stage}
  REGION: ${opt:region, self:provider.region}
  REDIRECT_CLIENT_URI: http://127.0.0.1:3000/
# Custom Redirect Domain
# REDIRECT_DOMAIN_NAME: ${opt:stage, self:provider.stage}.my-custom-domain-for-callback.com
# REDIRECT_CERTIFICATE_ARN: arn:aws:acm:us-east-1:111122223333:certificate/fb1b9770-a305-495d-aefb-27e5e101ff3
# REDIRECT_URI: https://${self:provider.environment.REDIRECT_DOMAIN_NAME}/authentication/callback/{provider}
# REDIRECT_HOSTED_ZONE_ID: XXXXXXXX
  TOKEN_SECRET: token-secret-123
# Database
  FAUNADB_SECRET: SERVER_SECRET_FOR_YOUR_FAUNADB_DATABASE
  CACHE_DB_NAME: ${self:service}-cache-${opt:stage, self:provider.stage}
  USERS_DB_NAME: ${self:service}-users-${opt:stage, self:provider.stage}
# Cognito
  USER_POOL_ID: user-pool-id
# Providers
  PROVIDER_FACEBOOK_ID: "fb-mock-id"
  PROVIDER_FACEBOOK_SECRET: "fb-mock-secret"
  PROVIDER_GOOGLE_ID: "g-mock-id"
  PROVIDER_GOOGLE_SECRET: "cg-mock-secret"
  PROVIDER_MICROSOFT_ID: "ms-mock-id"
  PROVIDER_MICROSOFT_SECRET: "ms-mock-secret"
  PROVIDER_CUSTOM_GOOGLE_ID: "cg-mock-id"
  PROVIDER_CUSTOM_GOOGLE_SECRET: "cg-mock-secret"

Example Provider Packages

Custom Provider

Package contains example /authentication/lib/custom-google.js how to implement a custom authentication provider using generic Provider class. To test custom provider go to http://laardee.github.io/serverless-authentication-gh-pages and click 'custom-google' button.

User database

To use FaunaDB to save user data. First create a database here, then:

  1. configure FAUNADB_SECRET in authentication/env.yml with a server secret for your database
  2. uncomment return faunaUser.saveUser(profile); from authentication/lib/storage/usersStorage.js
  3. change the last line of authentication/lib/storage/cacheStorage.js to module.exports = faunaCache;
  4. Run STAGE=dev npm run setup:fauna

To use DynamoBD to save user data:

  1. uncomment UsersTable block from authentication/serverless.yml resources
  2. uncomment return dynamoUser.saveUser(profile); from authentication/lib/storage/usersStorage.js

To use Cognito User Pool as user database:

  1. create new user pool (http://docs.aws.amazon.com/cognito/latest/developerguide/setting-up-cognito-user-identity-pools.html)
  2. copy user pool id to authentication/env.yml
  3. uncomment return saveCognito(profile); from authentication/lib/storage/usersStorage.js

API Gateway Custom Domain Name

If you have a domain, a hosted zone, and a certificate for the domain defined in your AWS account, you may use API Gateway Custom Domain Name in your setup.

Your domain name goes to the REDIRECT_DOMAIN_NAME environment variable, if this is set, CloudFormation will create a custom domain name to API Gateway and recordset to the Route 53

REDIRECT_DOMAIN_NAME: "authentication.my-domain.com"

Certificate ARN for your domain,

REDIRECT_CERTIFICATE_ARN: "arn:aws:acm:us-east-1:111122223333:certificate/fb1b9770-a305-495d-aefb-27e5e101ff3"

Callback path, leave this like it is

REDIRECT_URI: "https://${self:provider.environment.REDIRECT_DOMAIN_NAME}/authentication/callback/{provider}"

Route 53 hosted zone id, go to Route 53 and get the id from there or with CLI aws route53 list-hosted-zones --query 'HostedZones[*].[Name,Id]' --output text. The CLI will output something like this authentication.my-domain.com. /hostedzone/Z10QEETUEETUAO copy the Z10QEETUEETUAO part to the REDIRECT_HOSTED_ZONE_ID environment variable.

REDIRECT_HOSTED_ZONE_ID: "Z10QEETUEETUAO"

Running Tests

  • Run npm install in project root directory
  • Run npm test

serverless-authentication-boilerplate's People

Contributors

adrienlemaire avatar austencollins avatar cpoole avatar kidsil avatar laardee avatar raananw 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

serverless-authentication-boilerplate's Issues

how do you get the access_token?

I'm writing a custom provider, and looking at how to get access to the access_token in the callback respones. It looks buried in serverless-authentication which seems to return a profile, but no access_token. But maybe I'm missing something?

Using the authorization_token for authenticated requests

Hey there!

Thanks for the work on this project, it's great. Just one quick noob question!

After successfully authenticating with a 3rd party oauth service and receiving a 224 character authorization_token, how do I go about then using this to make authenticated requests to the third party's API? For example, getting the authenticated user's profile data.

Cheers for all your work and help!

J.

"before all" hook error when running ./specs-docker.sh

Have followed README line by line. When running the tests I get the following errors:

Setup specs
1) "before all" hook

Authentication
Signin
2) should fail to return token for invalid provider

All the Authentication Providers error as well. Serverless 1.0.2 installed. OSX El Capitan. Docker 1.12.1

Auth Tokens Question & Custom Provider Auth Token Expiration Issue

This is relatively minor and likely indicative of my lack of understanding, but the authorization and refresh tokens that are returned by the boilerplate, are these the actual tokens (access_token, refresh_token) that the provider has returned or representative of them?

Relatedly, are you overriding the Auth Token expiration time? Say if you customized the code to authorize with Spotify who returns an access_token and a refresh_token and the expiration on the access_token is 3600s, are you arbitrarily setting the new expiration (15s) or does that mean we can also extend it?

Thanks for any guidance in this matter

Mobile App friendly boilerplate

Hello,

This works great on the web. But it would be cool with a boilerplate for a "mobile app".
Where you don't use the redirect flows. Cause that's usually handled by the app and then the app will have a token that it would like to send to serverless-authentication

Any plans on that ? :)

Handling sign out?

I may be misunderstanding something here, but for security purposes, it seems like we'd want a handler that, on signout, immediately revokes the latest refresh and auth tokens so that if someone had either, they'd no longer work (particularly the refresh token). I see there's a revokeRefreshToken function in the cacheStorage.js example, which could work, but it also appears to create a new refresh token. (Which isn't really a problem as long as its not returned to the client.)

Basically I suppose I'm just curious: If I wanted to create my own signout handler to satisfy the security needs described above, what's the best approach to doing so?

Dynamo Cache token validation and expiration

Thanks so much for implementing the boilerplate, very helpful!

I saw that in the dynamo cache the existence of the token is not checked:

    const newRefreshToken = (data) => {
      const userId = data.Items[0].userId;
      const payload = data.Items[0].payload;

https://github.com/laardee/serverless-authentication-boilerplate/blob/master/authentication/lib/storage/dynamo/dynamoCache.js#L149

Added the following check:

  if (data.Count <= 0) return Promise.reject('Invalid token');

Also it looks like you can use expired tokens, the query does not restrict to expired=false:

      const params = {
        TableName: table,
        ProjectionExpression: '#token, #type, #userId',
        KeyConditionExpression: '#token = :token and #type = :type',
        ExpressionAttributeNames: {
          '#token': 'token',
          '#type': 'type',
          '#userId': 'userId'
        },
        ExpressionAttributeValues: {
          ':token': oldToken,
          ':type': 'REFRESH'
        }
      };

https://github.com/laardee/serverless-authentication-boilerplate/blob/master/authentication/lib/storage/dynamo/dynamoCache.js#L129

Changed params to:

      const params = {
        TableName: table,
        ProjectionExpression: '#token, #type, #userId, #expired',
        KeyConditionExpression: '#token = :token and #type = :type',
        FilterExpression: '#expired = :expired',
        ExpressionAttributeNames: {
          '#token': 'token',
          '#type': 'type',
          '#userId': 'userId',
          '#expired': 'expired'
        },
        ExpressionAttributeValues: {
          ':token': oldToken,
          ':type': 'REFRESH',
          ':expired': false
        }
      };

When will Cognito User Pools be supported

When requesting a new feature or enhancement, please be sure to include the following:

  • The reason why you think this new feature will help you and help other users as well

I'm very new to AWS and serverless but know I want to use serverless for the lambda part of my backend. My app, Brian is for older people who will not have accounts so federated access is no good. I saw that I could manage my own auth but that is more than I wish to take on. Then I discovered the Beta/Preview User Pools which are perfect. Or will be once stable. I can add federation later.

  • The reason why you think this new feature is relavent to the Serverless Framework (within scope)

I'm not clear on the road map for User Pools or how much churn their may yet be but I think they will be a great feature to extend the existing serverless support. It extends the options for authentication.

  • If you're familiar with our codebase, I'd be really helpful to share some design ideas on how to implement it, or better yet, open a PR!

Way beyond me but I guess it needs core support and then adding to the boilerplate

getting Serverless Error when trying to deploy

I'm getting the following error when running serverless deploy

  Serverless Error ---------------------------------------
 
     Trying to populate non string value into a string for
     variable ${self:provider.environment.SERVICE}. Please
     make sure the value of the property is a string.
 
  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
 
  Your Environment Information -----------------------------
     OS:                 linux
     Node Version:       4.3.2
     Serverless Version: 1.5.0

How to authenticate / authorize for a single Google domain?

Not being any sort of expert on oAuth, I can see that I can use this project to authenticate against Google's oAuth service for my various Google accounts.

However, if there's only one Google domain that I want to support login for (e.g. a G Suite domain for a business), but not the others, how would I go about configuring this?

I'd guess I'd use the Custom Google provider, but I couldn't find any mechanism for doing this.

Any pointers here would be much appreciated.

useful sequence diagrams

Here are 3 sequence diagrams of how this works, that you can plug into https://www.websequencediagrams.com/ when you are making slides or whatever.

title Authentication
Browser->Sign In: Initial request
Sign In -> Facebook: Redirect
note over Facebook: Approve login
Facebook -> Callback: Redirect
Callback -> FaunaDB: Find or create user
FaunaDB -> Callback: Database secret for user
Callback -> Browser: Set authorization header
title Authorization
Browser -> Content Service: API Request
Content Service -> Authorizer: Authorization to Policy
Authorizer -> Content Service: Policy w/ FaunaDB Secret
Content Service <-> FaunaDB: Load application data
Content Service -> Browser: Render API response
title Refresh
Browser -> Content Service: API Request
Content Service -> Authorizer: Authorization to Policy
Authorizer -> Content Service: Access denied
Content Service -> Browser: Access denied
Browser -> Refresh: XHR Request with refresh token
Refresh -> FaunaDB: Find user for token
FaunaDB -> Refresh: Database secret for user
Refresh -> Browser: Set Authorization Header

Looks like this:

authentication

authorization

refresh

Getting errors when do serverless deploy

serverless deploy --verbose

<--- Last few GCs --->

   57874 ms: Scavenge 1323.2 (1434.4) -> 1323.2 (1434.4) MB, 24.8 / 0 ms [allocation failure].
   57899 ms: Scavenge 1323.2 (1434.4) -> 1323.2 (1434.4) MB, 24.7 / 0 ms [allocation failure].
   57924 ms: Scavenge 1323.2 (1434.4) -> 1323.2 (1434.4) MB, 25.0 / 0 ms [allocation failure].
   57949 ms: Scavenge 1323.2 (1434.4) -> 1323.2 (1434.4) MB, 24.8 / 0 ms [allocation failure].
   57973 ms: Scavenge 1323.2 (1434.4) -> 1323.2 (1434.4) MB, 24.8 / 0 ms [allocation failure].


<--- JS stacktrace --->
Cannot get stack trace in GC.
FATAL ERROR: Scavenger: semi-space copy
 Allocation failed - process out of memory
[1]    47248 abort      serverless deploy --verbose

How to redirect to originating page?

Is there a way to redirect the user to his/her current position?

E.g. The user is on /cars. After he logs in i want him to be end up on /cars again.
If he is on /watches i want him to be redirected to /watches.

As far as i understand

"redirectClientURI": "http://url-to-frontend-webapp/"

determins the redirect URI. How can i make something like "redirectClientURI": "origin" work?

authentication by email/password

I need to enable authentication by email/password for my API. This is not basic http auth, as I need to verify the data from a MySQL database.

Would it make sense to create a new "provider" package serverless-authentication-database, that will generate some sort of authorization_token which will return the user id ?

There's a lot of security issues to worry about here, hence I'd love to get your input before I get started.

Callback request to authorization_uri ends up using http protocol with port 443

Hello, I'm having a problem where, even though my authorization_uri is set to an https address, when it ends up making the request, it formats the url like so: http://foo.bar.com:443/v1/token/jwt

Our endpoint ends up returning a moved permanently 301 because it does not start with https. Here's the set up I have in my custom provider (some values changed for privacy):

const callbackHandler = (event, config, callback) => {
  const myProvider = new Provider(config);
  const profileMap = response =>
    new Profile({
      id: response.id,
      provider: 'foo-sso',
      at: response.access_token
    });

  const options = {
    authorization_uri: 'https://foo.bar.com/v1/token/jwt',
    profile_uri: 'https://foo.bar.com/api/me',
    profileMap
  };

  myProvider.callback(
    event,
    options,
    { authorization: { grant_type: 'authorization_code' } },
    callback
  );
};

When I print out the response object from your serverless-authentication -> provider.js line 102
notice that the location of the response is http://foo.bar.com:443/v1/token/jwt/

location: 'http://foo.bar.com:443/v1/token/jwt/',
'content-length': '253',
connection: 'close',
'content-type': 'text/html; charset=iso-8859-1' } },
read: [Function],
body: '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">\n<html><head>\n<title>301 Moved Permanently</title>\n</head><body>\n<h1>Moved Permanently</h1>\n<p>The document has moved <a href="http://foo.bar.com:443/v1/token/jwt/">here</a>.</p>\n</body></html>\n' }

Do you have any idea of what might be happening here? I've dug into the request module and found some places where it established protocol and everything seems fine, I can't quite find where the post function is defined that is called in provider.js on line 101. If you could even help me find the definition of that post function that would help me greatly, so I can figure out when my authorization_uri gets changed to http protocol.

_request2.default.post(authorization_uri, { form: payload }, function (error, response, accessData) {

How to deal with CORS issues?

First of all, I know this is a general question of me rather than a real issue. The only reason I post here is I have a hard time finding a clear explanation on this.
I am trying to call the signIn method of this repository from my site by making "get" ajax call. However, I get the following error.

XMLHttpRequest cannot load https://9yh8kzx6b1.execute-api.us-east-
1.amazonaws.com/dev/authentication/signin/facebook. Redirect from 'https://9yh8kzx6b1.execute-
api.us-east-1.amazonaws.com/dev/authentication/signin/facebook' to 
'https://www.facebook.com/dialog/oauth?client_id=954130508021993&redirect_ur…
6cbad6184f6e45c5e50fe412d34593e8a896838dae54a4e3a3bc2270a6da647e991ded3539' has 
been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested 
resource. Origin 'http://mydomain.com' is therefore not allowed access.

Is there something I did wrong? I am not quite sure which part of the sign in process lacks the 'Access-Control-Allow-Origin' header. Is it my site (hosted on S3)? Is it the API gateway?

Cors headers in unauthorized response

Hello, I'm using your auth framwork and am very happy with it. I cannot seem to figure out how to get the unauthorized 401 messages to include cors headers. What do you recommend?

Create Custom provider

If I want to sign in to Flickr Oauth implementation I have to use the base of Custom Google or create new serverless-authentication-microsoft / serverless-authentication-facebook / serverless-authentication-google?

Cors header on authorized.

Hello, I'm using your auth framwork and am very happy with it. I cannot seem to figure out how to get the unauthorized 401 messages to include cors headers. What do you recommend?

Test-token folder sls deploy not finding authorizer arn

I am trying to sun sls deploy on the test-token folder but am getting

- Function not found: arn:aws:lambda:us-east-1:180971085012:function:uz4g3f3m8i.

previously I Installed the authentication sls and got

  GET - https://uz4g3f3m8i.execute-api.us-east-1.amazonaws.com/dev/authentication/signin/{provider}
  GET - https://uz4g3f3m8i.execute-api.us-east-1.amazonaws.com/dev/authentication/callback/{provider}
  GET - https://uz4g3f3m8i.execute-api.us-east-1.amazonaws.com/dev/authentication/refresh/{refresh_token}

Any ideas what else I can try?

Upgrade node version

Node 4 LTS end-of-life is near... Hopefully, v8 support for Lambda comes before that.

Feature: Custom Authorizer

This looks great for authorizing with different providers through an intermediary service, and setting up the endpoints to do so!

However, for using the auth-result of this with any other functions, and for re-usability, it seems like an ideal solution would be to use a "custom authorizer" to validate the credentials passed up for subsequent calls which would act as the middleware and pass the profile back to the lambda function.

The test app here appears to put the auth code inline which makes for a lot of duplicate boilerplate.

Authorizer Blueprints: https://github.com/awslabs/aws-apigateway-lambda-authorizer-blueprints/blob/master/blueprints/nodejs/index.js

I'm interested in discussing this, and potentially collaborating on a new project, or helping with this one...

It seems to me that Cognito and Auth0 can be very expensive, and open source Custom Authorizers would be an amazing alternative/cheap open source project to these pay solutions.

Example Deployment:

  • Add your config for 1) 3rd party key/secret to your main serverless.yml file, 2) storage preference, etc..
  • Import the node package within your functions folder.
  • Document how to make a create account endpoint (passing up valid 3rd party federated token)
  • Document how to use the library's authorizer to auto-auth and pass the profile to your main function on success. (Ex: https://github.com/eahefnawy/serverless-authorizer/blob/master/serverless.yml)

Multiple redirect URIs

I've been playing with this project for not so long so bare with me if this is more than a question than a feature request (it might as well be). I've been wondering how to have multiple redirect URIs (the case I have in mind is an OAuth flow on web that will redirect to https://my.domain.com/callback-route but also a mobile redirect (used by a mobile app via URL schemas like myapp://oauth-callback). This doesn't seem to be supported at this point, or am I missing something?

Facebook oauth from multiple devices

My facebook application has a website and an iOS application configured in its settings, but my serverless application only uses the website redirect client uri via process.env.REDIRECT_CLIENT_URI. I'm wondering how to handle the iOS case as well.
Do you have any suggestion ?

CORS plugin

Add CORS plugin as soon as it is updated to work with Serverless v.0.5.

Documentation?

The installation documentation is great, but where's the documentation on how to use it?

Developed React Front End with Authentication Per User

I've forked the latest version of the master branch as of today (11/02/2016) and integrated with the serverless-react-boilerplate. Features are:

  • Writes user data to user table.
  • Authenticates per user so that one user cannot modify another's data.
  • Authenticates user before responding with auth token to prevent hacking.

Working demo here: http://sls-react-auth.s3-website-us-east-1.amazonaws.com/ (facebook login only).

See: https://github.com/jcummins54/serverless-react-boilerplate
and https://github.com/jcummins54/serverless-authentication-boilerplate

Would be happy to collaborate to make this a branch here.

Why use Cognito User Pool at all? Shouldn't we use Federated Identity Pool?

I've been having trouble with Authorization (API Gateway) because of the password field. Diving a little deeper I've looked into the COGNITO_IDENTITY_POOL_ID variables that were added.

Since this boilerplate doesn't include User+Pass auth, is there any reason why we don't use Cognito Federated Identity Pools (as they seem to be more fitting for oauth providers)?

Set headers for a custom provider

I'm using a version of this to access the Harvest API and it requires that for a profile request, the Content-Type and Accept headers be set. As written, serverless-authentication/lib/providers.js doesn't provide for the capability to set special headers for a custom provider.

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.