Skip to content
Permalink
Browse files

Episode 29 - Login with GitHub with Buffalo (#179)

* Episode 29 - Login with GitHub with Buffalo

* removing subrepo tracker

* Adding real episode29 code

* more stuff

* adding the goth plugin

* stuff!

* Remove cruft

* adding web page for episode 29
  • Loading branch information...
arschles committed Aug 13, 2019
1 parent 8296b2c commit 74d79554d3ee2b183323d239d370f6f15173f99a
Showing with 7,786 additions and 0 deletions.
  1. +3 −0 episode29/.babelrc
  2. +21 −0 episode29/.buffalo.dev.yml
  3. +20 −0 episode29/.codeclimate.yml
  4. +3 −0 episode29/.dockerignore
  5. +28 −0 episode29/.gitignore
  6. +35 −0 episode29/Dockerfile
  7. +39 −0 episode29/README.md
  8. +24 −0 episode29/actions/actions_test.go
  9. +96 −0 episode29/actions/app.go
  10. +27 −0 episode29/actions/auth.go
  11. +9 −0 episode29/actions/home.go
  12. +8 −0 episode29/actions/home_test.go
  13. +28 −0 episode29/actions/render.go
  14. +118 −0 episode29/assets/css/_buffalo.scss
  15. +4 −0 episode29/assets/css/application.scss
  16. BIN episode29/assets/images/favicon.ico
  17. +721 −0 episode29/assets/images/logo.svg
  18. +6 −0 episode29/assets/js/application.js
  19. +13 −0 episode29/config/buffalo-app.toml
  20. +7 −0 episode29/config/buffalo-plugins.toml
  21. +13 −0 episode29/database.yml
  22. +32 −0 episode29/fixtures/sample.toml
  23. +34 −0 episode29/go.mod
  24. +1,017 −0 episode29/go.sum
  25. +15 −0 episode29/grifts/db.go
  26. +11 −0 episode29/grifts/init.go
  27. +3 −0 episode29/inflections.json
  28. +3 −0 episode29/locales/all.en-us.yaml
  29. +38 −0 episode29/main.go
  30. +22 −0 episode29/models/models.go
  31. +24 −0 episode29/models/models_test.go
  32. +40 −0 episode29/package.json
  33. +2 −0 episode29/public/robots.txt
  34. +14 −0 episode29/templates/_flash.plush.html
  35. +21 −0 episode29/templates/application.plush.html
  36. +64 −0 episode29/templates/index.plush.html
  37. +112 −0 episode29/webpack.config.js
  38. +5,090 −0 episode29/yarn.lock
  39. +21 −0 www/content/screencast/episode_29_buffalo_login_with_github_using_goth.md
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env"]
}
@@ -0,0 +1,21 @@
app_root: .
ignored_folders:
- vendor
- log
- logs
- assets
- public
- grifts
- tmp
- bin
- node_modules
- .sass-cache
included_extensions:
- .go
- .env
build_path: tmp
build_delay: 200ns
binary_name: episode29-build
command_flags: []
enable_colors: true
log_name: buffalo
@@ -0,0 +1,20 @@
engines:
fixme:
enabled: true
gofmt:
enabled: true
golint:
enabled: true
govet:
enabled: true
exclude_paths:
- grifts/**/*
- "**/*_test.go"
- "*_test.go"
- "**_test.go"
- logs/*
- public/*
- templates/*
ratings:
paths:
- "**.go"
@@ -0,0 +1,3 @@
node_modules/
*.log
bin/
@@ -0,0 +1,28 @@
vendor/
**/*.log
**/*.sqlite
.idea/
bin/
tmp/
node_modules/
.sass-cache/
*-packr.go
public/assets/
.vscode/
.grifter/
.env
**/.DS_Store
*.pid
coverage
coverage.data
.svn
.console_history
.sass-cache/*
.jhw-cache/
jhw.*
*.sublime*
node_modules/
dist/
generated/
.vendor/

@@ -0,0 +1,35 @@
# This is a multi-stage Dockerfile and requires >= Docker 17.05
# https://docs.docker.com/engine/userguide/eng-image/multistage-build/
FROM gobuffalo/buffalo:v0.14.8 as builder

RUN mkdir -p $GOPATH/src/episode29
WORKDIR $GOPATH/src/episode29

# this will cache the npm install step, unless package.json changes
ADD package.json .
ADD yarn.lock .
RUN yarn install --no-progress
ADD . .
ENV GO111MODULES=on
RUN go get ./...
RUN buffalo build --static -o /bin/app

FROM alpine
RUN apk add --no-cache bash
RUN apk add --no-cache ca-certificates

WORKDIR /bin/

COPY --from=builder /bin/app .

# Uncomment to run the binary in "production" mode:
# ENV GO_ENV=production

# Bind the app to 0.0.0.0 so it can be seen from outside the container
ENV ADDR=0.0.0.0

EXPOSE 3000

# Uncomment to run the migrations before running the binary:
# CMD /bin/app migrate; /bin/app
CMD exec /bin/app
@@ -0,0 +1,39 @@
# Building Login with GitHub into your Buffalo App

Go in 5 Minutes, episode 29.

Welcome back to the Buffalo series! The last Buffalo episode we did was [episode 25](https://www.goin5minutes.com/screencast/episode_25_buffalo_templating_with_plush/), where we talked about templating with [templating with Plush](https://gobuffalo.io/en/docs/templating/).

Today, we're going to continue talking about frontend technologies and look at how to let your users log into your webapp with GitHub

We're going to be using the [Goth library](https://gobuffalo.io/en/docs/goth) to do this, so I'll run through what that is, and then we'll look at the code for how to use it, and then we'll see it in action!

Check out the screencast for more!

# How To Set Up Goth with [`buffalo-goth`](https://github.com/gobuffalo/buffalo-goth)

With our Buffalo app created (I ran `buffalo new episode29` to create this very app!), we can use plugins to customize it. In this episode, we're going to use the `buffalo-goth` plugin to write most of the code for us to implement GitHub auth.

>These instructions are adapted from https://gobuffalo.io/en/docs/goth
First, get the `buffalo-goth` plugin for Buffalo. You'll only need to do this once, then you can re-use the plugin for all your Buffalo projects:

```console
$ go get github.com/gobuffalo/buffalo-goth
```

>The `buffalo-goth` executable is going to be put into `$GOPATH/bin`, so make sure that directory is in your `PATH`.
Next, generate the code for GitHub login:

```console
$ buffalo generate goth github
```

>You can pass more auth "providers" to the `buffalo generate goth` command. See [here](https://github.com/markbates/goth#supported-providers) for a complete list of providers.
# Show Notes

- [Buffalo docs on Goth](https://gobuffalo.io/en/docs/goth)
- [`buffalo-goth` code generator on GitHub](https://github.com/gobuffalo/buffalo-goth)
- [The Goth Library on GitHub](https://github.com/markbates/goth)
@@ -0,0 +1,24 @@
package actions

import (
"testing"

"github.com/gobuffalo/packr/v2"
"github.com/gobuffalo/suite"
)

type ActionSuite struct {
*suite.Action
}

func Test_ActionSuite(t *testing.T) {
action, err := suite.NewActionWithFixtures(App(), packr.New("Test_ActionSuite", "../fixtures"))
if err != nil {
t.Fatal(err)
}

as := &ActionSuite{
Action: action,
}
suite.Run(t, as)
}
@@ -0,0 +1,96 @@
package actions

import (
"github.com/gobuffalo/buffalo"
"github.com/gobuffalo/envy"
forcessl "github.com/gobuffalo/mw-forcessl"
paramlogger "github.com/gobuffalo/mw-paramlogger"
"github.com/unrolled/secure"

csrf "github.com/gobuffalo/mw-csrf"
i18n "github.com/gobuffalo/mw-i18n"
"github.com/gobuffalo/packr/v2"

"github.com/markbates/goth/gothic"
)

// ENV is used to help switch settings based on where the
// application is being run. Default is "development".
var ENV = envy.Get("GO_ENV", "development")
var app *buffalo.App
var T *i18n.Translator

// App is where all routes and middleware for buffalo
// should be defined. This is the nerve center of your
// application.
//
// Routing, middleware, groups, etc... are declared TOP -> DOWN.
// This means if you add a middleware to `app` *after* declaring a
// group, that group will NOT have that new middleware. The same
// is true of resource declarations as well.
//
// It also means that routes are checked in the order they are declared.
// `ServeFiles` is a CATCH-ALL route, so it should always be
// placed last in the route declarations, as it will prevent routes
// declared after it to never be called.
func App() *buffalo.App {
if app == nil {
app = buffalo.New(buffalo.Options{
Env: ENV,
SessionName: "_episode29_session",
})

setupGoth(app)

// Automatically redirect to SSL
app.Use(forceSSL())

// Log request parameters (filters apply).
app.Use(paramlogger.ParameterLogger)

// Protect against CSRF attacks. https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
// Remove to disable this.
app.Use(csrf.New)

// Wraps each request in a transaction.
// c.Value("tx").(*pop.Connection)
// Remove to disable this.
// app.Use(popmw.Transaction(models.DB))

// Setup and use translations:
app.Use(translations())

app.GET("/", HomeHandler)

auth := app.Group("/auth")
auth.GET("/{provider}", buffalo.WrapHandlerFunc(gothic.BeginAuthHandler))
auth.GET("/{provider}/callback", AuthCallback)
app.ServeFiles("/", assetsBox) // serve files from the public directory
}

return app
}

// translations will load locale files, set up the translator `actions.T`,
// and will return a middleware to use to load the correct locale for each
// request.
// for more information: https://gobuffalo.io/en/docs/localization
func translations() buffalo.MiddlewareFunc {
var err error
if T, err = i18n.New(packr.New("app:locales", "../locales"), "en-US"); err != nil {
app.Stop(err)
}
return T.Middleware()
}

// forceSSL will return a middleware that will redirect an incoming request
// if it is not HTTPS. "http://example.com" => "https://example.com".
// This middleware does **not** enable SSL. for your application. To do that
// we recommend using a proxy: https://gobuffalo.io/en/docs/proxy
// for more information: https://github.com/unrolled/secure/
func forceSSL() buffalo.MiddlewareFunc {
return forcessl.Middleware(secure.Options{
SSLRedirect: ENV == "production",
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
})
}
@@ -0,0 +1,27 @@
package actions

import (
"fmt"
"os"

"github.com/gobuffalo/buffalo"
"github.com/markbates/goth"
"github.com/markbates/goth/gothic"
"github.com/markbates/goth/providers/github"
)

func setupGoth(app *buffalo.App) {
// gothic.Store = app.SessionStore
goth.UseProviders(
github.New(os.Getenv("GITHUB_KEY"), os.Getenv("GITHUB_SECRET"), fmt.Sprintf("http://127.0.0.1:3000/auth/github/callback")),
)
}

func AuthCallback(c buffalo.Context) error {
user, err := gothic.CompleteUserAuth(c.Response(), c.Request())
if err != nil {
return c.Error(401, err)
}
// Do something with the user, maybe register them/sign them in
return c.Render(200, r.JSON(user))
}
@@ -0,0 +1,9 @@
package actions

import "github.com/gobuffalo/buffalo"

// HomeHandler is a default handler to serve up
// a home page.
func HomeHandler(c buffalo.Context) error {
return c.Render(200, r.HTML("index.html"))
}
@@ -0,0 +1,8 @@
package actions

func (as *ActionSuite) Test_HomeHandler() {
res := as.HTML("/").Get()

as.Equal(200, res.Code)
as.Contains(res.Body.String(), "Welcome to Buffalo")
}
@@ -0,0 +1,28 @@
package actions

import (
"github.com/gobuffalo/buffalo/render"
"github.com/gobuffalo/packr/v2"
)

var r *render.Engine
var assetsBox = packr.New("app:assets", "../public")

func init() {
r = render.New(render.Options{
// HTML layout to be used for all HTML requests:
HTMLLayout: "application.plush.html",

// Box containing all of the templates:
TemplatesBox: packr.New("app:templates", "../templates"),
AssetsBox: assetsBox,

// Add template helpers here:
Helpers: render.Helpers{
// for non-bootstrap form helpers uncomment the lines
// below and import "github.com/gobuffalo/helpers/forms"
// forms.FormKey: forms.Form,
// forms.FormForKey: forms.FormFor,
},
})
}

0 comments on commit 74d7955

Please sign in to comment.
You can’t perform that action at this time.