Skip to content

Instantly share code, notes, and snippets.

@danielberkompas
Created March 4, 2017 20:44
Show Gist options
  • Save danielberkompas/9822197a8cec66ff011d24ab32e687cf to your computer and use it in GitHub Desktop.
Save danielberkompas/9822197a8cec66ff011d24ab32e687cf to your computer and use it in GitHub Desktop.
An example of how to hack together Ueberauth.Auth structs
defmodule MyApp.Auth do
@moduledoc """
Creates `Ueberauth.Auth` structs from OAuth responses.
This module is an ugly hack which is necessary because `Ueberauth` doesn't provide
the necessary hooks to get such a struct without giving it control of the whole
callback phase. We can't do this in the API because all the mobile app can give us
is the OAuth token.
Most of the code was lifted from Ueberauth, with minor changes as needed.
"""
def new(type, token, secret \\ nil)
def new(:facebook, token, _secret) do
{_module, config} = Application.get_env(:ueberauth, Ueberauth)[:providers][:facebook]
client = Ueberauth.Strategy.Facebook.OAuth.client
token = OAuth2.AccessToken.new(token, client)
case OAuth2.AccessToken.get(token, "/me?fields=#{config[:profile_fields]}") do
{:ok, %OAuth2.Response{status_code: status_code, body: user}} when status_code in 200..399 ->
{:ok, parse(:facebook, user, token)}
{:ok, %OAuth2.Response{status_code: 401}} ->
{:error, "Not authorized."}
{:error, %OAuth2.Error{reason: reason}} ->
{:error, reason}
_other ->
{:error, "An unknown error occurred."}
end
end
def new(:twitter, token, secret) do
params = [include_entities: false, skip_status: true, include_email: true]
case Ueberauth.Strategy.Twitter.OAuth.get("/1.1/account/verify_credentials.json", params, {token, secret}) do
{:ok, {{_, status_code, _}, _, body}} when status_code in 200..399 ->
user =
body
|> List.to_string
|> Poison.decode!
{:ok, parse(:twitter, user, {token, secret})}
{:ok, {{_, 401, _}, _, _}} ->
{:error, "Not authorized."}
{:ok, {_, _, body}} ->
body =
body
|> List.to_string
|> Poison.decode!
error = List.first(body["errors"])
{:error, error}
end
end
def new(:google, token, _secret) do
client = Ueberauth.Strategy.Google.OAuth.client
token = OAuth2.AccessToken.new(token, client)
case OAuth2.AccessToken.get(token, "https://www.googleapis.com/plus/v1/people/me/openIdConnect") do
{:ok, %OAuth2.Response{status_code: status_code, body: user}} when status_code in 200..399 ->
{:ok, parse(:google, user, token)}
{:ok, %OAuth2.Response{status_code: 401, body: _body}} ->
{:error, "Not authorized."}
{:error, %OAuth2.Error{reason: reason}} ->
{:error, reason}
end
end
defp parse(:facebook, user, token) do
scopes = token.other_params["scope"] || ""
scopes = String.split(scopes, ",")
%Ueberauth.Auth{
provider: :facebook,
strategy: Ueberauth.Strategy.Facebook,
uid: user["id"],
info: %Ueberauth.Auth.Info{
description: user["bio"],
email: user["email"],
first_name: user["first_name"],
image: "http://graph.facebook.com/#{user["id"]}/picture?type=square",
last_name: user["last_name"],
name: user["name"],
urls: %{
facebook: user["link"],
website: user["website"]
}
},
extra: %Ueberauth.Auth.Extra{
raw_info: %{
token: token,
user: user
}
},
credentials: %Ueberauth.Auth.Credentials{
expires: token.expires_at != nil,
expires_at: token.expires_at,
scopes: scopes,
token: token.access_token
}
}
end
defp parse(:twitter, user, {token, secret}) do
%Ueberauth.Auth{
provider: :twitter,
strategy: Ueberauth.Strategy.Twitter,
uid: user["id_str"],
info: %Ueberauth.Auth.Info{
email: user["email"],
image: user["profile_image_url"],
name: user["name"],
nickname: user["screen_name"],
description: user["description"],
urls: %{
Twitter: "https://twitter.com/#{user["screen_name"]}",
Website: user["url"]
}
},
extra: %Ueberauth.Auth.Extra{
raw_info: %{
token: token,
user: user
}
},
credentials: %Ueberauth.Auth.Credentials{
token: token,
secret: secret
}
}
end
defp parse(:google, user, token) do
scopes = String.split(token.other_params["scope"] || "", ",")
%Ueberauth.Auth{
provider: :google,
strategy: Ueberauth.Strategy.Google,
uid: user["sub"],
info: %Ueberauth.Auth.Info{
email: user["email"],
first_name: user["given_name"],
image: user["picture"],
last_name: user["family_name"],
name: user["name"],
urls: %{
profile: user["profile"],
website: user["hd"]
}
},
extra: %Ueberauth.Auth.Extra{
raw_info: %{
token: token,
user: user
}
},
credentials: %Ueberauth.Auth.Credentials{
expires: token.expires_at != nil,
expires_at: token.expires_at,
scopes: scopes,
refresh_token: token.refresh_token,
token: token.access_token
}
}
end
end
@danielberkompas
Copy link
Author

You can check the latest version of the uberauth docs for how to do part of what you’re describing. https://hexdocs.pm/ueberauth/Ueberauth.html

For the rest, it would be quite a bit of work to update this in the way you’re asking, and I don’t have time, unfortunately. I recommend you look through uberauth docs and blog posts for help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment