Giter Club home page Giter Club logo

login-with's Introduction

Build Status Coverage Status

About

Stateless authentication microservice for "login-with" functionality, supporting:

  • Twitter
  • GitHub
  • Reddit
  • Facebook
  • Google
  • LinkedIn
  • Instagram
  • Mixer
  • Spotify
  • Strava
  • AppleID
  • ... more to come (PRs welcome)

You can deploy with now or Docker (for mandatory and optional env variables see below).

$ now lipp/login-with
$ docker run lipp/login-with

This microservice must run in a subdomain of yours, e.g. login.yourdomain.com.

<a href='https://login.yourdomain.com/twitter?success=ON_SUCCESS_URL&failure=ON_FAILURE_URL'>
  Login with Twitter
</a>

On successful login two cookies will be created:

  • jwt - A "JSON Web Token" (JWT) containing profile information and the respective access tokens (Twitter/etc). http-only!
  • profile - A JSON string which containing non-sensitive information (accessible from browser JS):
    • username - string / mandatory, the account specific user alias (e.g. Twitter name)
    • photo - string / optional, the account specific user image link
    • name - string / optional, the "real" name

The cookies will be available for your toplevel domain and all subdomains. In addition, the cookie's secure flag is set, which means that your other websites/webservices must run over https.

Supported by

If you want to easily add token-based authentication to your apps, feel free to check out Auth0's SDKs and free plan at auth0.com/overview Auth0 logo.

Setup

The configuration is done by means of environment variables.

Mandatory environment variables

  • LW_SESSION_SECRET - The session secret used by the microservice
  • LW_JWT_SECRET - The secret to sign the JSON Web Token (JWT)
  • LW_SUBDOMAIN - The subdomain this microservice runs, e.g. login.yourdomain.com. All other subdomains (e.g. api.yourdomain.com) and the top-level (e.g. yourdomain.com)

Optional environment variables

  • LW_COOKIE_MAXAGE - The max age of the store cookie, defaults to 10 days
  • LW_PROFILE_COOKIENAME - The profile's cookie name, defaults to profile
  • LW_JWT_COOKIENAME - The JSON Web Token's (JWT) cookie name, defaults to jwt
  • LW_DYNAMIC_SCOPE - When set allows you to customize the scopes used in an authentication request, defaults to off
  • LW_COOKIE_DOMAIN - The explicit cookie domain, e.g. .foo.com. If not specified this will derive from LW_SUBDOMAIN, e.g. if LW_SUBDOMAIN=login.foo.com then the cookie domain "defaults" to .foo.com. This is ok unless you have multi level subdomain for (LW_SUBDOMAIN=dev.login.foo.com). In this case you must explicitly set LW_COOKIE_DOMAIN=.foo.com as .login.foo.com would be the auto guessed value.

GitHub specific environment variables

You need to create your own GitHub OAuth application. If LW_SUBDOMAIN=login.yourdomain.com your Authorization callback URL must be: https://login.yourdomain.com/github/callback

  • LW_GITHUB_CLIENTID - Your GitHub Client ID
  • LW_GITHUB_CLIENTSECRET - Your GitHub Client Secret

Google specific environment variables

You need to create your own Google OAuth application. If LW_SUBDOMAIN=login.yourdomain.com your Authorization callback URL must be: https://login.yourdomain.com/google/callback

  • LW_GOOGLE_CLIENTID - Your Google Client ID
  • LW_GOOGLE_CLIENTSECRET - Your Google Client Secret

Facebook specific environment variables

You need to create your own Facebook login application. If LW_SUBDOMAIN=login.yourdomain.com your allowed redirects must be: https://login.yourdomain.com/facebook/callback

  • LW_FACEBOOK_APPID - Your Facebook App ID
  • LW_FACEBOOK_APPSECRET - Your Facebook App Secret

LinkedIn specific environment variables

You need to create your own LinkedIn OAuth2 application. If LW_SUBDOMAIN=login.yourdomain.com your Authorization callback URL must be: https://login.yourdomain.com/linkedin/callback

  • LW_LINKEDIN_CLIENTID - Your LinkedIn Client ID
  • LW_LINKEDIN_CLIENTSECRET - Your LinkedIn Client Secret

Reddit specific environment variables

You need to create your own Reddit OAuth application. If LW_SUBDOMAIN=login.yourdomain.com your Authorization callback URL must be: https://login.yourdomain.com/reddit/callback

  • LW_REDDIT_CLIENTID - Your Reddit Client ID
  • LW_REDDIT_CLIENTSECRET - Your Reddit Client Secret

Twitter specific environment variables

You need to create your own Twitter OAuth application. If LW_SUBDOMAIN=login.yourdomain.com your Authorization callback URL must be: https://login.yourdomain.com/twitter/callback

  • LW_TWITTER_CONSUMERKEY - Your Twitter Consumer Key
  • LW_TWITTER_CONSUMERSECRET - Your Twitter Consumer Secret

Mixer specific environment variables

You need to create your own Mixer OAuth Client. If LW_SUBDOMAIN=login.yourdomain.com your Authorization callback URL must be: https://login.yourdomain.com/mixer/callback

  • LW_MIXER_CLIENTID - Your Mixer Client ID
  • LW_MIXER_CLIENTSECRET - Your Mixer Client Secret
  • LW_MIXER_SCOPE - Specify which scopes the authorization request with Mixer should have. Check Mixer's documentation for scopes.

Instagram specific environment variables

You need to create your own Instagram OAuth application. If LW_SUBDOMAIN=login.yourdomain.com your Authorization callback URL must be: https://login.yourdomain.com/instagram/callback

  • LW_INSTAGRAM_CLIENTID - Your Instagram Client ID
  • LW_INSTAGRAM_CLIENTSECRET - Your Instagram Client Secret

Spotify specific environment variables

You need to create your own Spotify OAuth application. If LW_SUBDOMAIN=login.yourdomain.com is your Authorization callback URL must be: https://login.yourdomain.com/spotify/callback

  • LW_SPOTIFY_CLIENTID - Your Spotify Client ID
  • LW_SPOTIFY_CLIENTSECRET - Your Spotify Client Secret

Strava specific environment variables

You need to create your own Strava OAuth application. If LW_SUBDOMAIN=login.yourdomain.com your Authorization callback URL must be: https://login.yourdomain.com/strava/callback

  • LW_STRAVA_CLIENTID - Your Strava Client ID
  • LW_STRAVA_CLIENTSECRET - Your Strava Client Secret

AppleID specific environment variables

You need to be Apple Developer:

  • LW_APPLE_TEAMID - Team ID at your membership page
  • LW_APPLE_KEYID - register new key. Add "Sign in with Apple" capability, download key. it downloads only once
  • LW_APPLE_KEYLOCATION - path to key file relative to your server
  • LW_APPLE_SERVICEID - register Services ID
  • LW_APPLE_CALLBACK - enable "Sign in with Apple" capability in service you created, configure your callback url (should be like: https://yourwebsite.com/apple/callback)

Endpoints

  • /twitter - login with Twitter account (if configured through env variables)
  • /facebook - login with Facebook account (if configured through env variables)
  • /github - login with GitHub account (if configured through env variables)
  • /google - login with Google account (if configured through env variables)
  • /reddit - login with Reddit account (if configured through env variables)
  • /mixer - login with Mixer account (if configured through env variables)
  • /linkedin - login with LinkedIn account (if configured through env variables)
  • /instagram - login with Instagram account (if configured through env variables)
  • /spotify - login with Spotify account (if configured through env variables)
  • /strava - login with Strava account (if configured through env variables)
  • /apple - login with AppleID (if configured through env variables)
  • /logout - logout and clears the respective cookies

All endpoints expect the query parameters:

  • success A url to redirect to in case of successful login (use encodeURIComponent for proper escaping)
  • failure A url to redirect to in case of failed login (use encodeURIComponent for proper escaping)

Don't forget to encodeURIComponent on them.

Testing

Say you deployed your login-with container with:

  • correct environment variables
  • properly configured services (e.g. Twitter callback)
  • served via https on auth.your-domain.com

Then you can test everything by just "visiting" your login strategy with the browser, e.g. https://auth.your-domain.com/twitter. In case of success, you will be finally redirected and see the contents of your profile as JSON. In case of error, the error will be shown as JSON.

Example

Visit login-with.com. The source code is here.

Deployment with now

Note: You need a custom domain to run this microservice with now. Chrome (and maybe other browsers) explicitly prevent usage of wildcard cookies on .now.sh, which are required for this microservice to work.

  1. Create your secrets for the environment variables
  2. Deploy, e.g. with now
now lipp/login-with \
	-e NODE_ENV=production \
	-e LW_SUBDOMAIN=login.yourdomain.com \
	-e LW_SESSION_SECRET=@lw-session-secret \
	-e LW_JWT_SECRET=@lw-token-secret \
	-e LW_REDDIT_CLIENTID=@lw-reddit-clientid \
	-e LW_REDDIT_CLIENTSECRET=@lw-reddit-clientsecret \
	-e LW_GITHUB_CLIENTID=@lw-github-clientid \
	-e LW_GITHUB_CLIENTSECRET=@lw-github-clientsecret \
	-e LW_TWITTER_CONSUMERKEY=@lw-twitter-consumerkey \
	-e LW_TWITTER_CONSUMERSECRET=@lw-twitter-consumersecret \
	-e LW_INSTAGRAM_CLIENTID=@lw-instagram-clientid \
	-e LW_INSTAGRAM_CLIENTSECRET=@lw-instagram-clientsecret \
	--alias login.yourdomain.com

Deployment with Docker

  1. Create your secrets for the environment variables
  2. Deploy, e.g. with Docker
docker run lipp/login-with -p 80:3000 \
	-e NODE_ENV=production \
	-e LW_SUBDOMAIN=login.yourdomain.com \
	-e LW_SESSION_SECRET=@lw-session-secret \
	-e LW_JWT_SECRET=@lw-token-secret \
	-e LW_REDDIT_CLIENTID=@lw-reddit-clientid \
	-e LW_REDDIT_CLIENTSECRET=@lw-reddit-clientsecret \
	-e LW_GITHUB_CLIENTID=@lw-github-clientid \
	-e LW_GITHUB_CLIENTSECRET=@lw-github-clientsecret \
	-e LW_TWITTER_CONSUMERKEY=@lw-twitter-consumerkey \
	-e LW_TWITTER_CONSUMERSECRET=@lw-twitter-consumersecret \
	-e LW_INSTAGRAM_CLIENTID=@lw-instagram-clientid \
	-e LW_INSTAGRAM_CLIENTSECRET=@lw-instagram-clientsecret \

login-with's People

Contributors

dependabot[bot] avatar doeixd avatar jcguarinpenaranda avatar jeffreylo avatar jonespen avatar kahwee avatar lipp avatar luanmuniz avatar matteo-hertel avatar probableprime avatar slavaganzin avatar stevenharman avatar tomkp avatar vitosamson 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

login-with's Issues

The demo github login fails

When I try to log into github on the demo application (https://login-with.now.sh/login) the server responds with:-

{"error":{"name":"AuthorizationError","message":"The redirect_uri MUST match the registered callback URL for this application.","code":"redirect_uri_mismatch","uri":"https://developer.github.com/v3/oauth/#redirect-uri-mismatch","status":500}}

Issue with multi dot subdomains

Hi there,

thanks for this awesome project!

I just noticed that if you use multiple subdomains (multi dot subdomains) like this one:

dev.login.mydomain.com

You will get a cookie for .login.mydomain.com. I don't think this is intentional, since a cookie for .login.mydomain.com is not really useful ;)

Extracting a multidot subdomain from a domain is not trivial, since there are TLDs (or second level domains) like co.uk, that also contain a dot.

I googled around and found out that there is a public maintained list with all TLDs:

https://publicsuffix.org/

There are also tools that use the list to parse domain names, e.g.:

https://github.com/wrangr/psl

It looks like wrangr/psl does not have any dependencies and might be save for use. It uses MIT license as well.

README typo

The README says "Your Google Client ID" and "Your Google Client Secret" in the LinkedIn section.

No love for Microsoft?

Microsoft login support would be awesome. A lot of people have Office365, and other MS services just like Google...

session-memory-store

I saw you using a no more mantained in-memory store module for the express-session.

I recommend switching to a fully-tested one, check it out: memorystore

Discuss: Security concerns

I think it's unsafe to leave sensitive data such as access tokens (in the case of Oauth2 like Google).

If an attacker is able to retrieve a cookie he can easily decode the JWT token and use the access token to issue arbitrary requests to the authentication provider APIs and retrieve any information that might have been originally granted to it by the user (e.g. read my Gmail emails...).

I think the point of this lib is to make this kind of authentication processes stateless (or backendless) and storing the access tokens directly in the cookie is an easy win. Anyway I would at least try to protect this sensitive data by applying some level of encryption, maybe a simple symmetric encryption, using the same secret used to generate the JWT token signature as key would enough...

I look forward to knowing the community thoughts on this matter

Error! No secret found by uid or name XXX

I ran now lipp/login-with -e LW_SESSION_SECRET=... -e LW_JWT_SECRET=... -e LW_SUBDOMAIN=... -e LW_FACEBOOK_APPID=... -e FACEBOOK_APPSECRET=..., but still got the error Error! No secret found by uid or name "lw-reddit-clientsecret" (and the error changes every time). It looks like all env vars are required, even the optional ones?

Make cookie content customizable

Let the user configure, which meta data per strategy is included in jwt and/or profile cookie.

Maybe by using env variables LW_GOOGLE_JWT_META=email,hobby,animal.

See also #36

initial values on mandatory env variables

Hello!,

I want to test your oauth authentication using docker the thing is that i'm new into docker, i have red several docs but in the end i have no clue about which initial values do mandatory environment variables need in order to compile in terminal?

I need some guidance.

Here is my screen with my setup.

mmm

And here is the other screen with the terminal error.

docker error

it says cant find env variable, but i put it in my set up, please, help.

Different Scopes

If I wanted to request different scopes is it just better to fork and modify the strategies or is there another way that scope can be configured? I didn't seem to see anything in the code that suggested it would be configured by an environment variable, but that might make for a good feature?

How to identify a returning user? Should provider-id not be added in token?

Hello,

I have a simple question. Say I've logged in once and got a JWT, and then log in on another machine using the same social account. Maybe I'm mistaken, but I can't find any way to (easily) tell that both tokens belong to the same person since the provider ID doesn't seem to be stored in the token. So is there a way to identify a user without having to make a request to the provider API with the given access token?

_src disabled?

It's open-source and deployed on now.sh, so why is the _src URL disabled?

Not seeing cookies

Great work!

I tried this out on my local, and I don't see any cookies saved. I just see "{}" when I visit the "auth" endpoint. Everything seems to work, as I get redirected to Github's oauth page, and then back. Then, I tried it on your site, https://login-with.now.sh/login , and I see the same thing. Everything appears to work, and your app is my Github authorized Apps ( https://github.com/settings/applications ), along with my app. I did a console.log(user) under

onAuthenticationCallback: (req, res, next) => { const type = req.path.split('/')[1] passport.authenticate(type, (error, user) => {

and the user is there, in the format that is set up in github.js.

I tried a try/catch around the res.cookie section, and there were no exceptions.

Any ideas?

Reddit strategy doesn't redirect to failure URL on declined auth request

To reproduce:

  1. Go to https://login-with.com/login
  2. Login with Reddit
  3. Hit the "decline" button on the reddit auth request page

You'll get redirected to https://auth.login-with.com/reddit/callback with {"error":null,"user":false}

This is happening because in routes.js here, both error and user are falsy and so it falls through to the res.json at the end.

A solution here would probably be to change line 34 to if (error || !user) - would you accept a PR for that? I'm not sure if this is happening for other providers, I've only tested with reddit.

Email authentication

This looks super great, thanks ๐Ÿ‘

I want to migrate my app which has Facebook and email + password auth. Do you plan to add auth using email link and/or login/password?

What is it exactly?

I wrote this on a Show HN about this, but was (correctly) called out for not opening an issue about that:

The information on /login should probably be on / so I can read somewhere what "Stateless authentication microservice" actually means.
Also maybe a sentence why this is neat and should be used...

Someone else wrote:

"Stateless authentication microservice" has only one possible meaning to me. Did you want to ask something more specific, or do you just not know what those (common) words mean?
reply

to which I then replied

The me it means... nothing specific.
It tells me that is has something to do with login, "without state" (whatever this means in this context) and that it is somehow not a "big service" but very "micro", so probably independent. Stateless and microservice can mean so many things.

So please take this as a bit of feedback: Not everyone really and fully understand the current description.

Scopes

Given a login-with instance how could an application request additional scopes for the authorisation request?

Should we allow this?

I work for a streaming site that has a lot of varied scopes, sometimes just having the user's record isn't enough.

I've taken a stab at this here: ProbablePrime@a6e0d30 but wanted to open an issue before the PR to see if this was something that would be welcome.

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.