This tutorial will show you how to obtain an access token for a user through their google account. You can use this for doing things like connecting to google docs, drive, analytics, and a ton of other things. Maybe you want to make a form that stores data in google sheets. Or you might want to build your own custom dashboard that shows your site's google analytics data. Whatever the case, you'll need the access token after a user has authenticated with google.
To start this, we will just pull the master branch of Lucky with Crystal 0.26.1. Since these things are changing all the time, there is a chance that by the time you read this, it may all be out of date. Sorry!
If you don't already have crystal installed, check out the installation guide.
Step 1
We need to get our lucky cli tool.
git clone https://github.com/luckyframework/lucky_cli.git
cd lucky_cli
crystal build --release ./src/lucky.cr
mv ./lucky /usr/local/bin/
Step 2
Now that we have a lucky cli tool, we can generate the lucky app. cd
in to your directory of choice and then...
lucky init
> Project name? google_auth
> API only or full support for HTML and Webpack? (api/full): full
> Generate authentication? (y/n): n
cd google_auth
./bin/setup
lucky dev
Woot! If the browser window opened up to localhost:3001 with a Lucky Welcome Page, then you're all good. If not, come have a chat with us so we can figure out what's wrong.
Step 3
Ok, now that you have a running app, we have a baseline just in case something doesn't work from this point on. Feel free to git
this thing up with a branch or something.
We need to add a new shard to help us do most of the heavy lifting. Add in the multi_auth shard to your shard.yml
file.
dependencies:
#...
multi_auth:
github: msa7/multi_auth
branch: master
# ...
NOTE: At the time I originally wrote this stuff, I found a bug. If this PR isn't merged, you may need to use my fork
Now that you have that added, be sure to run shards install
to install that shard.
Step 4
Time to add some code! Create this file in your config/
directory
# config/multi_auth_handler.cr
require "multi_auth"
class MultiAuthHandler
MultiAuth.config("google", ENV["GOOGLE_OAUTH_ID"], ENV["GOOGLE_OAUTH_SECRET"])
def self.authorize_uri(provider : String)
MultiAuth.make(provider, "#{Lucky::RouteHelper.settings.base_uri}/oauth/#{provider}/callback").authorize_uri(scope: "profile")
end
def self.user(provider : String, params : Enumerable({String, String}))
MultiAuth.make(provider, "#{Lucky::RouteHelper.settings.base_uri}/oauth/#{provider}/callback").user(params)
end
end
This class sets up your MultiAuth config, and then gives you 2 convenience methods. The first authorize_uri
generates the URL your user is redirected to which in this case is google. The second user
is the OAuth'd user that google returns.
Next up let's make some pages.
Edit the src/actions/home/index.cr
file.
class Home::Index < BrowserAction
get "/" do
token = session.get?(:token) || "" # add this line
render Home::IndexPage, token: token # update this line
end
end
This just tells Lucky to use your custom IndexPage instead of the default one.
Create a src/pages/home/index_page.cr
file.
class Home::IndexPage < MainLayout
needs token : String
def content
h1 @token
div do
link "Login", to: OAuth::Handler.with("google")
end
end
end
This is your shiny new home page with a link to login.
Create a src/actions/oauth/handler.cr
file.
class OAuth::Handler < BrowserAction
get "/oauth/:provider" do
redirect to: MultiAuthHandler.authorize_uri(provider)
end
end
This action redirects the user to google to select their google account.
Create a src/actions/oauth/callback.cr
file.
class OAuth::Callback < BrowserAction
get "/oauth/:provider/callback" do
user = MultiAuthHandler.user(provider, request.query_params)
if user.access_token
session.set(:token, user.access_token.as(OAuth2::AccessToken).access_token)
flash.success = "It worked!"
else
flash.failure = "That did not work"
end
redirect to: Home::Index
end
end
This action is hit when the user leaves google and comes back to your lucky app. We pass in the params that google sends to us, and then get the user info. If the user has an access_token
, then we set that token in to our user session. The flash
will be the message displayed to the user if this worked or not. (Hopefully it worked). Finally we just redirect to the home page.
That's actually all of the code we need to do this. There's a few bits we're missing though. So if you tried to run the code at this point, you'll probably see some exceptions blowing up.
Step 5
We're just running this all in development, but for development, google won't let you redirect to localhost. That's fine though, we can easily get around that. We're going to "pretend" our app domain is actually http://google-auth.lvh.me:3001
. lvh.me
is a special domain setup to point back to your local computer. The nice thing is it looks like a real domain, gives you the ability to use a subdomain, and you can still access your dev site with no other configurations. Though, we do need to change 1 thing.
Open up config/watch.yml
and update to this
host: google-auth.lvh.me
port: 3001
Back in the first file we added, there was a line of code Lucky::RouteHelper.settings.base_uri
. This points back to this watch file in local development. By default it would be 0.0.0.0
which is usually fine; however, in this case we're building a URL to tell google to send us back to. We want google to send us back to http://google-auth.lvh.me:3001/oauth/google/callback
. If we don't update this watch.yml, google would try to send us back to http://0.0.0.0:5000/oauth/google/callback
, and google will yell at you.
Lastly, there was mention of 2 environment variables ENV["GOOGLE_OAUTH_ID"]
, ENV["GOOGLE_OAUTH_SECRET"]
. We need to actually obtain these. I'd say this is probably the most difficult part of the whole thing.
- Register your app - https://console.developers.google.com/
- Generate OAuth credentials - https://console.developers.google.com/apis/credentials
- Enable Google People API - https://console.developers.google.com/apis/api/people.googleapis.com/overview
If you get stuck on these steps, there's tons of different links. I suggest google search for "google oauth credentials".
Once you have your "OAuth 2.0 client IDs" setup under Credentials, you'll need to update the Authorized redirect URIs section and add in http://google-auth.lvh.me:3001
. That will allow google to safely redirect you back to your lucky app.
If you have your oauth keys at this point, head back to your lucky code, and add a new .env
file in the root of your project.
GOOGLE_OAUTH_ID=your_oauth_client_id
GOOGLE_OAUTH_SECRET=your_oauth_client_secret
That should be it! Make sure your app is booted, go to the home page, and click on "Login". You'll be taken to google to select your account and agree that "Google auth app wants to look at your profile data". After you accept, you will be redirected back to the home page of your lucky app with a giant h1 tag showing your access token.
Now that you understand the basics, it's time to build your real app, and actually make it pretty and functional!
Top comments (1)
Excellent write up!