Browse files

Refactor common code

  • Loading branch information...
1 parent 574627e commit e67610c22663ad77063e725d44cc8397ecbc4995 @dvv committed Mar 20, 2013
View
44 README.md
@@ -18,46 +18,28 @@ Router configuration
--------------
```erlang
-{"/auth/google/:action", cowboy_social_google, [
+{"/auth/google/:action", cowboy_social, [
+ {provider, cowboy_social_google},
% At the end of the flow this handler will be called as
% Mod:Fun({ok, Auth, Profile}, Req) or Mod:Fun({error, Reason}, Req)
{handler, {Mod, Fun}},
- {client_id, <<"440647648374.apps.googleusercontent.com">>},
+ {client_id, <<"...">>},
{client_secret, <<"...">>},
{scope, <<"https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile">>},
{callback_uri, <<"/auth/google/callback">>}
]}.
-{"/auth/github/:action", cowboy_social_github, [
- {handler, {Mod, Fun}},
- {client_id, <<"883b68d607abddc24f77">>},
- {client_secret, <<"...">>},
- {scope, <<>>},
- {callback_uri, <<"/auth/github/callback">>}
-]}.
-{"/auth/yandex/:action", cowboy_social_yandex, [
- {handler, {Mod, Fun}},
- {client_id, <<"f44bd59ddfbe408ab1d29151126385a6">>},
- {client_secret, <<"...">>},
- {scope, <<>>},
- {callback_uri, <<"/auth/yandex/callback">>}
-]}.
-{"/auth/vkontakte/:action", cowboy_social_vkontakte, [
- {handler, {Mod, Fun}},
- {client_id, <<"3473116">>},
- {client_secret, <<"...">>},
- {scope, <<"uid,first_name,last_name,sex,photo">>},
- {callback_uri, <<"/auth/vkontakte/callback">>}
-]}.
-{"/auth/mailru/:action", cowboy_social_mailru, [
- {handler, {Mod, Fun}},
- {client_id, <<"701614">>},
- {client_secret, <<"...">>},
- {secret_key, <<"...">>},
- {scope, <<>>},
- {callback_uri, <<"/auth/mailru/callback">>}
-]}.
```
+Supported providers
+--------------
+- Github
+- Google
+- Mail.ru
+- PayPal
+- Vkontakte
+- Yandex
+- add more, this very simple
+
License (MIT)
-------
View
2 src/cowboy_request.erl
@@ -56,7 +56,7 @@ request(Method, URL, Headers, Body) ->
% pecypc_log:info({reqerr, _Else}),
{error, failed}
end,
-% pecypc_log:info({res, _ResHeaders, Result}),
+% pecypc_log:info({res, Result}),
Result.
urlencode(Bin) when is_binary(Bin) ->
View
86 src/cowboy_social.erl
@@ -15,99 +15,73 @@
%%
init(_Transport, Req, Opts) ->
- {ok, Req, Opts}.
+ % compose full redirect URI
+ case key(callback_uri, Opts) of
+ << "http://", _/binary >> -> {ok, Req, Opts};
+ << "https://", _/binary >> -> {ok, Req, Opts};
+ Relative ->
+ {SelfUri, Req2} = cowboy_req:host_url(Req),
+ {ok, Req2, lists:keyreplace(callback_uri, 1, Opts,
+ {callback_uri, << SelfUri/binary, Relative/binary >>})}
+ end.
terminate(_Reason, _Req, _State) ->
ok.
-%%
-%% {"/auth/:provider/:action", cowboy_social, [...]}.
-%%
handle(Req, Opts) ->
- Provider = key(provider, Opts),
% extract flow action name
{Action, Req2} = cowboy_req:binding(action, Req),
- % construct callback URI
- {SelfUri, Req3} = cowboy_req:host_url(Req2),
- [FullPath] = cowboy_req:get([path], Req3),
- CallbackUrl = << SelfUri/binary, FullPath/binary >>,
% perform flow action
- {ok, Req4} = handle_request(Action, Provider, Opts, CallbackUrl, Req3),
- {ok, Req4, undefined}.
+ {ok, Req3} = handle_request(Action, Req2, Opts),
+ {ok, Req3, undefined}.
%%
%% redirect to provider authorization page, expect it to redirect
%% to our next handler
%%
-handle_request(<<"login">>, P, O, U, Req) ->
- AuthUrl = << (cowboy_social_providers:authorize_url(P))/binary, $?,
- (cowboy_request:urlencode([
- {<<"client_id">>, key(client_id, O)},
- {<<"redirect_uri">>, binary:replace(U, <<"/login">>, <<"/callback">>)},
- {<<"response_type">>, <<"code">>},
- {<<"scope">>, key(scope, O)}
- ]))/binary >>,
- cowboy_req:reply(303, [{<<"location">>, AuthUrl}], <<>>, Req);
+handle_request(<<"login">>, Req, Opts) ->
+ cowboy_req:reply(302, [
+ {<<"location">>, (key(provider, Opts)):get_authorize_url(Opts)}
+ ], <<>>, Req);
%%
%% provider redirected back to us with authorization code
%%
-handle_request(<<"callback">>, P, O, U, Req) ->
+handle_request(<<"callback">>, Req, Opts) ->
case cowboy_req:qs_val(<<"code">>, Req) of
{undefined, Req2} ->
- finish({error, nocode}, Req2);
+ finish({error, nocode}, Req2, Opts);
{Code, Req2} ->
- get_access_token(P, O, U, Code, Req2)
+ get_access_token(Code, Req2, Opts)
end;
%%
%% catchall
%%
-handle_request(_, _, _, _, Req) ->
+handle_request(_, Req, _) ->
{ok, Req2} = cowboy_req:reply(404, [], <<>>, Req),
{ok, Req2, undefined}.
%%
%% exchange authorization code for auth token
%%
-get_access_token(P, O, U, Code, Req) ->
- case cowboy_request:post_for_json(cowboy_social_providers:token_url(P), [
- {<<"code">>, Code},
- {<<"client_id">>, key(client_id, O)},
- {<<"client_secret">>, key(client_secret, O)},
- {<<"redirect_uri">>, U},
- {<<"grant_type">>, <<"authorization_code">>}
- ])
- of
- {ok, Auth} ->
- get_user_profile(P, O, Auth, Req);
- _ ->
- finish({error, notoken}, Req)
- end.
+get_access_token(Code, Req, Opts) ->
+ {ok, Auth} = (key(provider, Opts)):get_access_token(Code, Opts),
+ get_user_profile(Auth, Req, Opts).
%%
-%% use auth tocken to extract info from user profile
-%%
-get_user_profile(P, O, Auth, Req) ->
- AccessToken = key(<<"access_token">>, Auth),
- case cowboy_request:get_json(cowboy_social_providers:profile_url(P), [
- {<<"access_token">>, AccessToken}
- | cowboy_social_providers:custom_data(P, AccessToken, O)
- ])
- of
- {ok, Profile} ->
- finish({ok, cowboy_social_providers:normalize_profile(P, Auth, Profile)},
- Req);
- _ ->
- finish({error, noprofile}, Req)
- end.
+%% use auth token to extract info from user profile
+%%
+get_user_profile(Auth, Req, Opts) ->
+ {ok, Profile} = (key(provider, Opts)):get_user_profile(Auth, Opts),
+ finish({ok, Auth, Profile}, Req, Opts).
%%
%% finalize application flow by calling callback handler
%%
-finish(Status, Req) ->
- {{M, F}, Req2} = cowboy_req:meta(callback, Req),
- M:F(Status, Req2).
+finish(Status, Req, Opts) ->
+ {M, F} = key(handler, Opts),
+ M:F(Status, Req).
%%
%%------------------------------------------------------------------------------
View
154 src/cowboy_social_github.erl
@@ -5,104 +5,62 @@
-module(cowboy_social_github).
-author('Vladimir Dronnikov <dronnikov@gmail.com>').
--behaviour(cowboy_http_handler).
--export([init/3, terminate/3, handle/2]).
+-export([
+ get_authorize_url/1,
+ get_access_token/2,
+ get_user_profile/2
+ ]).
%%
%%------------------------------------------------------------------------------
%% OAUTH2 Application flow
%%------------------------------------------------------------------------------
%%
-init(_Transport, Req, Opts) ->
- % compose full redirect URI
- {SelfUri, Req2} = cowboy_req:host_url(Req),
- {ok, Req2, lists:keyreplace(callback_uri, 1, Opts,
- {callback_uri, << SelfUri/binary, (key(callback_uri, Opts))/binary >>})}.
-
-terminate(_Reason, _Req, _State) ->
- ok.
-
-handle(Req, Opts) ->
- % extract flow action name
- {Action, Req2} = cowboy_req:binding(action, Req),
- % perform flow action
- {ok, Req3} = handle_request(Action, Req2, Opts),
- {ok, Req3, undefined}.
-
-%%
-%% redirect to provider authorization page, expect it to redirect
-%% to our next handler
-%%
-handle_request(<<"login">>, Req, Opts) ->
- AuthUrl = << (authorize_url())/binary, $?,
- (cowboy_request:urlencode([
- {<<"client_id">>, key(client_id, Opts)},
- {<<"redirect_uri">>, key(callback_uri, Opts)},
- {<<"scope">>, key(scope, Opts)}
- ]))/binary >>,
- cowboy_req:reply(303, [{<<"location">>, AuthUrl}], <<>>, Req);
-
-%%
-%% provider redirected back to us with authorization code
-%%
-handle_request(<<"callback">>, Req, Opts) ->
- case cowboy_req:qs_val(<<"code">>, Req) of
- {undefined, Req2} ->
- finish({error, nocode}, Req2, Opts);
- {Code, Req2} ->
- get_access_token(Code, Req2, Opts)
- end;
-
%%
-%% catchall
+%% get URL of provider authorization page
%%
-handle_request(_, Req, _) ->
- {ok, Req2} = cowboy_req:reply(404, [], <<>>, Req),
- {ok, Req2, undefined}.
+get_authorize_url(Opts) ->
+ << "https://github.com/login/oauth/authorize", $?,
+ (cowboy_request:urlencode([
+ {client_id, key(client_id, Opts)},
+ {redirect_uri, key(callback_uri, Opts)},
+ {scope, key(scope, Opts)}
+ ]))/binary >>.
%%
%% exchange authorization code for auth token
%%
-get_access_token(Code, Req, Opts) ->
- try cowboy_request:post_for_json(token_url(), [
- {<<"code">>, Code},
- {<<"client_id">>, key(client_id, Opts)},
- {<<"client_secret">>, key(client_secret, Opts)},
- {<<"redirect_uri">>, key(callback_uri, Opts)}
- ])
- of
- {ok, Auth} ->
- get_user_profile(Auth, Req, Opts);
- _ ->
- finish({error, notoken}, Req, Opts)
- catch _:_ ->
- finish({error, notoken}, Req, Opts)
- end.
-
-%%
-%% use auth token to extract info from user profile
-%%
-get_user_profile(Auth, Req, Opts) ->
- AccessToken = key(<<"access_token">>, Auth),
- try cowboy_request:get_json(profile_url(), [
- {<<"access_token">>, AccessToken}
- ])
- of
- {ok, Profile} ->
- finish({ok, normalize_auth(Auth), normalize_profile(Profile)}, Req, Opts);
- _ ->
- finish({error, noprofile}, Req, Opts)
- catch _:_ ->
- finish({error, noprofile}, Req, Opts)
- end.
+get_access_token(Code, Opts) ->
+ {ok, Auth} = cowboy_request:post_for_json(
+ <<"https://github.com/login/oauth/access_token">>, [
+ {code, Code},
+ {client_id, key(client_id, Opts)},
+ {client_secret, key(client_secret, Opts)},
+ {redirect_uri, key(callback_uri, Opts)}
+ ]),
+ {ok, [
+ {access_token, key(<<"access_token">>, Auth)},
+ {token_type, key(<<"token_type">>, Auth)},
+ {expires_in, 0}
+ ]}.
%%
-%% finalize application flow by calling callback handler
+%% extract info from user profile
%%
-finish(Status, Req, Opts) ->
- {M, F} = key(handler, Opts),
- M:F(Status, Req).
+get_user_profile(Auth, _Opts) ->
+ {ok, Profile} = cowboy_request:get_json(
+ <<"https://api.github.com/user">>, [
+ {access_token, key(access_token, Auth)}
+ ]),
+ {ok, [
+ {id, << "github:",
+ (list_to_binary(integer_to_list(key(<<"id">>, Profile))))/binary >>},
+ {provider, <<"github">>},
+ {email, key(<<"email">>, Profile)},
+ {name, key(<<"name">>, Profile)},
+ {avatar, key(<<"avatar_url">>, Profile)}
+ ]}.
%%
%%------------------------------------------------------------------------------
@@ -113,35 +71,3 @@ finish(Status, Req, Opts) ->
key(Key, List) ->
{_, Value} = lists:keyfind(Key, 1, List),
Value.
-
-%%
-%%------------------------------------------------------------------------------
-%% Provider details
-%%------------------------------------------------------------------------------
-%%
-
-authorize_url() ->
- <<"https://github.com/login/oauth/authorize">>.
-
-token_url() ->
- <<"https://github.com/login/oauth/access_token">>.
-
-profile_url() ->
- <<"https://api.github.com/user">>.
-
-normalize_auth(Auth) ->
- [
- {access_token, key(<<"access_token">>, Auth)},
- {token_type, key(<<"token_type">>, Auth)},
- {expires_in, 0}
- ].
-
-normalize_profile(Raw) ->
- [
- {id, << "github:",
- (list_to_binary(integer_to_list(key(<<"id">>, Raw))))/binary >>},
- {provider, <<"github">>},
- {email, key(<<"email">>, Raw)},
- {name, key(<<"name">>, Raw)},
- {avatar, key(<<"avatar_url">>, Raw)}
- ].
View
160 src/cowboy_social_google.erl
@@ -5,106 +5,65 @@
-module(cowboy_social_google).
-author('Vladimir Dronnikov <dronnikov@gmail.com>').
--behaviour(cowboy_http_handler).
--export([init/3, terminate/3, handle/2]).
+-export([
+ get_authorize_url/1,
+ get_access_token/2,
+ get_user_profile/2
+ ]).
%%
%%------------------------------------------------------------------------------
%% OAUTH2 Application flow
%%------------------------------------------------------------------------------
%%
-init(_Transport, Req, Opts) ->
- % compose full redirect URI
- {SelfUri, Req2} = cowboy_req:host_url(Req),
- {ok, Req2, lists:keyreplace(callback_uri, 1, Opts,
- {callback_uri, << SelfUri/binary, (key(callback_uri, Opts))/binary >>})}.
-
-terminate(_Reason, _Req, _State) ->
- ok.
-
-handle(Req, Opts) ->
- % extract flow action name
- {Action, Req2} = cowboy_req:binding(action, Req),
- % perform flow action
- {ok, Req3} = handle_request(Action, Req2, Opts),
- {ok, Req3, undefined}.
-
-%%
-%% redirect to provider authorization page, expect it to redirect
-%% to our next handler
%%
-handle_request(<<"login">>, Req, Opts) ->
- AuthUrl = << (authorize_url())/binary, $?,
- (cowboy_request:urlencode([
- {<<"client_id">>, key(client_id, Opts)},
- {<<"redirect_uri">>, key(callback_uri, Opts)},
- {<<"response_type">>, <<"code">>},
- {<<"scope">>, key(scope, Opts)}
- ]))/binary >>,
- cowboy_req:reply(303, [{<<"location">>, AuthUrl}], <<>>, Req);
-
-%%
-%% provider redirected back to us with authorization code
+%% get URL of provider authorization page
%%
-handle_request(<<"callback">>, Req, Opts) ->
- case cowboy_req:qs_val(<<"code">>, Req) of
- {undefined, Req2} ->
- finish({error, nocode}, Req2, Opts);
- {Code, Req2} ->
- get_access_token(Code, Req2, Opts)
- end;
-
-%%
-%% catchall
-%%
-handle_request(_, Req, _) ->
- {ok, Req2} = cowboy_req:reply(404, [], <<>>, Req),
- {ok, Req2, undefined}.
+get_authorize_url(Opts) ->
+ << "https://accounts.google.com/o/oauth2/auth", $?,
+ (cowboy_request:urlencode([
+ {client_id, key(client_id, Opts)},
+ {redirect_uri, key(callback_uri, Opts)},
+ {response_type, <<"code">>},
+ {scope, key(scope, Opts)}
+ ]))/binary >>.
%%
%% exchange authorization code for auth token
%%
-get_access_token(Code, Req, Opts) ->
- try cowboy_request:post_for_json(token_url(), [
- {<<"code">>, Code},
- {<<"client_id">>, key(client_id, Opts)},
- {<<"client_secret">>, key(client_secret, Opts)},
- {<<"redirect_uri">>, key(callback_uri, Opts)},
- {<<"grant_type">>, <<"authorization_code">>}
- ])
- of
- {ok, Auth} ->
- get_user_profile(Auth, Req, Opts);
- _ ->
- finish({error, notoken}, Req, Opts)
- catch _:_ ->
- finish({error, notoken}, Req, Opts)
- end.
-
-%%
-%% use auth token to extract info from user profile
-%%
-get_user_profile(Auth, Req, Opts) ->
- AccessToken = key(<<"access_token">>, Auth),
- try cowboy_request:get_json(profile_url(), [
- {<<"access_token">>, AccessToken}
- ])
- of
- {ok, Profile} ->
- finish({ok, normalize_auth(Auth), normalize_profile(Profile)}, Req, Opts);
- _ ->
- finish({error, noprofile}, Req, Opts)
- catch _:_ ->
- finish({error, noprofile}, Req, Opts)
- end.
+get_access_token(Code, Opts) ->
+ {ok, Auth} = cowboy_request:post_for_json(
+ <<"https://accounts.google.com/o/oauth2/token">>, [
+ {code, Code},
+ {client_id, key(client_id, Opts)},
+ {client_secret, key(client_secret, Opts)},
+ {redirect_uri, key(callback_uri, Opts)},
+ {grant_type, <<"authorization_code">>}
+ ]),
+ {ok, [
+ {access_token, key(<<"access_token">>, Auth)},
+ {token_type, key(<<"token_type">>, Auth)},
+ {expires_in, key(<<"expires_in">>, Auth)}
+ ]}.
%%
-%% finalize application flow by calling callback handler
+%% extract info from user profile
%%
-finish(Status, Req, Opts) ->
- {M, F} = key(handler, Opts),
- M:F(Status, Req).
+get_user_profile(Auth, _Opts) ->
+ {ok, Profile} = cowboy_request:get_json(
+ <<"https://www.googleapis.com/oauth2/v1/userinfo">>, [
+ {access_token, key(access_token, Auth)}
+ ]),
+ {ok, [
+ {id, << "google:", (key(<<"id">>, Profile))/binary >>},
+ {provider, <<"google">>},
+ {email, key(<<"email">>, Profile)},
+ {name, key(<<"name">>, Profile)},
+ {avatar, key(<<"picture">>, Profile)},
+ {gender, key(<<"gender">>, Profile)},
+ {locale, key(<<"locale">>, Profile)}
+ ]}.
%%
%%------------------------------------------------------------------------------
@@ -115,36 +74,3 @@ finish(Status, Req, Opts) ->
key(Key, List) ->
{_, Value} = lists:keyfind(Key, 1, List),
Value.
-
-%%
-%%------------------------------------------------------------------------------
-%% Provider details
-%%------------------------------------------------------------------------------
-%%
-
-authorize_url() ->
- <<"https://accounts.google.com/o/oauth2/auth">>.
-
-token_url() ->
- <<"https://accounts.google.com/o/oauth2/token">>.
-
-profile_url() ->
- <<"https://www.googleapis.com/oauth2/v1/userinfo">>.
-
-normalize_auth(Auth) ->
- [
- {access_token, key(<<"access_token">>, Auth)},
- {token_type, key(<<"token_type">>, Auth)},
- {expires_in, key(<<"expires_in">>, Auth)}
- ].
-
-normalize_profile(Raw) ->
- [
- {id, << "google:", (key(<<"id">>, Raw))/binary >>},
- {provider, <<"google">>},
- {email, key(<<"email">>, Raw)},
- {name, key(<<"name">>, Raw)},
- {avatar, key(<<"picture">>, Raw)},
- {gender, key(<<"gender">>, Raw)},
- {locale, key(<<"locale">>, Raw)}
- ].
View
169 src/cowboy_social_mailru.erl
@@ -5,113 +5,75 @@
-module(cowboy_social_mailru).
-author('Vladimir Dronnikov <dronnikov@gmail.com>').
--behaviour(cowboy_http_handler).
--export([init/3, terminate/3, handle/2]).
+-export([
+ get_authorize_url/1,
+ get_access_token/2,
+ get_user_profile/2
+ ]).
%%
%%------------------------------------------------------------------------------
%% OAUTH2 Application flow
%%------------------------------------------------------------------------------
%%
-init(_Transport, Req, Opts) ->
- % compose full redirect URI
- {SelfUri, Req2} = cowboy_req:host_url(Req),
- {ok, Req2, lists:keyreplace(callback_uri, 1, Opts,
- {callback_uri, << SelfUri/binary, (key(callback_uri, Opts))/binary >>})}.
-
-terminate(_Reason, _Req, _State) ->
- ok.
-
-handle(Req, Opts) ->
- % extract flow action name
- {Action, Req2} = cowboy_req:binding(action, Req),
- % perform flow action
- {ok, Req3} = handle_request(Action, Req2, Opts),
- {ok, Req3, undefined}.
-
-%%
-%% redirect to provider authorization page, expect it to redirect
-%% to our next handler
%%
-handle_request(<<"login">>, Req, Opts) ->
- AuthUrl = << (authorize_url())/binary, $?,
- (cowboy_request:urlencode([
- {<<"client_id">>, key(client_id, Opts)},
- {<<"redirect_uri">>, key(callback_uri, Opts)},
- {<<"response_type">>, <<"code">>}
- ]))/binary >>,
- cowboy_req:reply(303, [{<<"location">>, AuthUrl}], <<>>, Req);
-
-%%
-%% provider redirected back to us with authorization code
+%% get URL of provider authorization page
%%
-handle_request(<<"callback">>, Req, Opts) ->
- case cowboy_req:qs_val(<<"code">>, Req) of
- {undefined, Req2} ->
- finish({error, nocode}, Req2, Opts);
- {Code, Req2} ->
- get_access_token(Code, Req2, Opts)
- end;
-
-%%
-%% catchall
-%%
-handle_request(_, Req, _) ->
- {ok, Req2} = cowboy_req:reply(404, [], <<>>, Req),
- {ok, Req2, undefined}.
+get_authorize_url(Opts) ->
+ << "https://connect.mail.ru/oauth/authorize", $?,
+ (cowboy_request:urlencode([
+ {client_id, key(client_id, Opts)},
+ {redirect_uri, key(callback_uri, Opts)},
+ {response_type, <<"code">>}
+ ]))/binary >>.
%%
%% exchange authorization code for auth token
%%
-get_access_token(Code, Req, Opts) ->
- try cowboy_request:post_for_json(token_url(), [
- {<<"code">>, Code},
- {<<"client_id">>, key(client_id, Opts)},
- {<<"client_secret">>, key(client_secret, Opts)},
- {<<"redirect_uri">>, key(callback_uri, Opts)},
- {<<"grant_type">>, <<"authorization_code">>}
- ])
- of
- {ok, Auth} ->
- get_user_profile(Auth, Req, Opts);
- _ ->
- finish({error, notoken}, Req, Opts)
- catch _:_ ->
- finish({error, notoken}, Req, Opts)
- end.
+get_access_token(Code, Opts) ->
+ {ok, Auth} = cowboy_request:post_for_json(
+ <<"https://connect.mail.ru/oauth/token">>, [
+ {code, Code},
+ {client_id, key(client_id, Opts)},
+ {client_secret, key(client_secret, Opts)},
+ {redirect_uri, key(callback_uri, Opts)},
+ {grant_type, <<"authorization_code">>}
+ ]),
+ {ok, [
+ {access_token, key(<<"access_token">>, Auth)},
+ {token_type, key(<<"token_type">>, Auth)},
+ {expires_in, key(<<"expires_in">>, Auth)}
+ ]}.
%%
-%% use auth token to extract info from user profile
+%% extract info from user profile
%%
-get_user_profile(Auth, Req, Opts) ->
+get_user_profile(Auth, Opts) ->
Sig = md5hex(<<
"app_id=", (key(client_id, Opts))/binary,
"method=users.getInfosecure=1session_key=",
- (key(<<"access_token">>, Auth))/binary,
+ (key(access_token, Auth))/binary,
(key(secret_key, Opts))/binary >>),
- try cowboy_request:get_json(profile_url(), [
- {<<"app_id">>, key(client_id, Opts)},
- {<<"method">>, <<"users.getInfo">>},
- {<<"secure">>, <<"1">>},
- {<<"session_key">>, key(<<"access_token">>, Auth)},
- {<<"sig">>, Sig}
- ])
- of
- {ok, Profile} ->
- finish({ok, normalize_auth(Auth), normalize_profile(Profile)}, Req, Opts);
- _ ->
- finish({error, noprofile}, Req, Opts)
- catch _:_ ->
- finish({error, noprofile}, Req, Opts)
- end.
-
-%%
-%% finalize application flow by calling callback handler
-%%
-finish(Status, Req, Opts) ->
- {M, F} = key(handler, Opts),
- M:F(Status, Req).
+ % NB: provider returns list of data for uids; we need only the first
+ {ok, [Profile]} = cowboy_request:get_json(
+ <<"http://www.appsmail.ru/platform/api">>, [
+ {app_id, key(client_id, Opts)},
+ {method, <<"users.getInfo">>},
+ {secure, <<"1">>},
+ {session_key, key(access_token, Auth)},
+ {sig, Sig}
+ ]),
+ {ok, [
+ {id, << "mailru:", (key(<<"uid">>, Profile))/binary >>},
+ {provider, <<"mailru">>},
+ {email, key(<<"email">>, Profile)},
+ {name, << (key(<<"first_name">>, Profile))/binary, " ",
+ (key(<<"last_name">>, Profile))/binary >>},
+ {avatar, key(<<"pic">>, Profile)},
+ {gender, case key(<<"sex">>, Profile) of
+ 1 -> <<"female">>; _ -> <<"male">> end}
+ ]}.
%%
%%------------------------------------------------------------------------------
@@ -126,36 +88,3 @@ key(Key, List) ->
md5hex(Bin) ->
list_to_binary(lists:flatten([io_lib:format("~2.16.0b",[N]) ||
N <- binary_to_list(erlang:md5(binary_to_list(Bin)))])).
-
-%%
-%%------------------------------------------------------------------------------
-%% Provider details
-%%------------------------------------------------------------------------------
-%%
-
-authorize_url() ->
- <<"https://connect.mail.ru/oauth/authorize">>.
-
-token_url() ->
- <<"https://connect.mail.ru/oauth/token">>.
-
-profile_url() ->
- <<"http://www.appsmail.ru/platform/api">>.
-
-normalize_auth(Auth) ->
- [
- {access_token, key(<<"access_token">>, Auth)},
- {token_type, key(<<"token_type">>, Auth)},
- {expires_in, key(<<"expires_in">>, Auth)}
- ].
-
-normalize_profile([Raw]) ->
- [
- {id, << "mailru:", (key(<<"uid">>, Raw))/binary >>},
- {provider, <<"mailru">>},
- {email, key(<<"email">>, Raw)},
- {name, << (key(<<"first_name">>, Raw))/binary, " ",
- (key(<<"last_name">>, Raw))/binary >>},
- {avatar, key(<<"pic">>, Raw)},
- {gender, case key(<<"sex">>, Raw) of 1 -> <<"female">>; _ -> <<"male">> end}
- ].
View
75 src/cowboy_social_paypal.erl
@@ -0,0 +1,75 @@
+%%
+%% @doc Handler for social login via PayPal.
+%%
+
+-module(cowboy_social_paypal).
+-author('Vladimir Dronnikov <dronnikov@gmail.com>').
+
+-export([
+ get_authorize_url/1,
+ get_access_token/2,
+ get_user_profile/2
+ ]).
+
+%%
+%%------------------------------------------------------------------------------
+%% OAUTH2 Application flow
+%%------------------------------------------------------------------------------
+%%
+
+%%
+%% get URL of provider authorization page
+%%
+get_authorize_url(Opts) ->
+ << "https://identity.x.com/xidentity/resources/authorize", $?,
+ (cowboy_request:urlencode([
+ {client_id, key(client_id, Opts)},
+ {redirect_uri, key(callback_uri, Opts)},
+ {response_type, <<"code">>},
+ {scope, key(scope, Opts)}
+ ]))/binary >>.
+
+%%
+%% exchange authorization code for auth token
+%%
+get_access_token(Code, Opts) ->
+ {ok, Auth} = cowboy_request:post_for_json(
+ <<"https://identity.x.com/xidentity/oauthtokenservice">>, [
+ {code, Code},
+ {client_id, key(client_id, Opts)},
+ {client_secret, key(client_secret, Opts)},
+ {redirect_uri, key(callback_uri, Opts)},
+ {grant_type, <<"authorization_code">>}
+ ]),
+ {ok, [
+ {access_token, key(<<"access_token">>, Auth)},
+ {token_type, <<"Bearer">>},
+ {expires_in, key(<<"expires_in">>, Auth)}
+ ]}.
+
+%%
+%% extract info from user profile
+%%
+get_user_profile(Auth, _Opts) ->
+ {ok, Result} = cowboy_request:get_json(
+ <<"https://identity.x.com/xidentity/resources/profile/me">>, [
+ {oauth_token, key(access_token, Auth)}
+ ]),
+ % NB: provider returns {status: ..., identity: Profile}
+ Profile = key(<<"identity">>, Result),
+ {ok, [
+ {id, << "paypal:", (key(<<"userId">>, Profile))/binary >>},
+ {provider, <<"paypal">>},
+ {email, hd(key(<<"emails">>, Profile))},
+ {name, key(<<"fullName">>, Profile)}
+ ]}.
+
+%%
+%%------------------------------------------------------------------------------
+%% Helpers
+%%------------------------------------------------------------------------------
+%%
+
+key(Key, List) ->
+ {_, Value} = lists:keyfind(Key, 1, List),
+ Value.
View
168 src/cowboy_social_vkontakte.erl
@@ -5,106 +5,70 @@
-module(cowboy_social_vkontakte).
-author('Vladimir Dronnikov <dronnikov@gmail.com>').
--behaviour(cowboy_http_handler).
--export([init/3, terminate/3, handle/2]).
+-export([
+ get_authorize_url/1,
+ get_access_token/2,
+ get_user_profile/2
+ ]).
%%
%%------------------------------------------------------------------------------
%% OAUTH2 Application flow
%%------------------------------------------------------------------------------
%%
-init(_Transport, Req, Opts) ->
- % compose full redirect URI
- {SelfUri, Req2} = cowboy_req:host_url(Req),
- {ok, Req2, lists:keyreplace(callback_uri, 1, Opts,
- {callback_uri, << SelfUri/binary, (key(callback_uri, Opts))/binary >>})}.
-
-terminate(_Reason, _Req, _State) ->
- ok.
-
-handle(Req, Opts) ->
- % extract flow action name
- {Action, Req2} = cowboy_req:binding(action, Req),
- % perform flow action
- {ok, Req3} = handle_request(Action, Req2, Opts),
- {ok, Req3, undefined}.
-
-%%
-%% redirect to provider authorization page, expect it to redirect
-%% to our next handler
-%%
-handle_request(<<"login">>, Req, Opts) ->
- AuthUrl = << (authorize_url())/binary, $?,
- (cowboy_request:urlencode([
- {<<"client_id">>, key(client_id, Opts)},
- {<<"redirect_uri">>, key(callback_uri, Opts)},
- {<<"response_type">>, <<"code">>}
- ]))/binary >>,
- cowboy_req:reply(303, [{<<"location">>, AuthUrl}], <<>>, Req);
-
-%%
-%% provider redirected back to us with authorization code
-%%
-handle_request(<<"callback">>, Req, Opts) ->
- case cowboy_req:qs_val(<<"code">>, Req) of
- {undefined, Req2} ->
- finish({error, nocode}, Req2, Opts);
- {Code, Req2} ->
- get_access_token(Code, Req2, Opts)
- end;
-
%%
-%% catchall
+%% get URL of provider authorization page
%%
-handle_request(_, Req, _) ->
- {ok, Req2} = cowboy_req:reply(404, [], <<>>, Req),
- {ok, Req2, undefined}.
+get_authorize_url(Opts) ->
+ << "https://oauth.vk.com/authorize", $?,
+ (cowboy_request:urlencode([
+ {client_id, key(client_id, Opts)},
+ {redirect_uri, key(callback_uri, Opts)},
+ {response_type, <<"code">>},
+ {scope, key(scope, Opts)}
+ ]))/binary >>.
%%
%% exchange authorization code for auth token
%%
-get_access_token(Code, Req, Opts) ->
- try cowboy_request:post_for_json(token_url(), [
- {<<"code">>, Code},
- {<<"client_id">>, key(client_id, Opts)},
- {<<"client_secret">>, key(client_secret, Opts)},
- {<<"redirect_uri">>, key(callback_uri, Opts)},
- {<<"grant_type">>, <<"authorization_code">>}
- ])
- of
- {ok, Auth} ->
- get_user_profile(Auth, Req, Opts);
- _ ->
- finish({error, notoken}, Req, Opts)
- catch _:_ ->
- finish({error, notoken}, Req, Opts)
- end.
-
-%%
-%% use auth token to extract info from user profile
-%%
-get_user_profile(Auth, Req, Opts) ->
- AccessToken = key(<<"access_token">>, Auth),
- try cowboy_request:get_json(profile_url(), [
- {<<"access_token">>, AccessToken},
- {<<"fields">>, key(scope, Opts)}
- ])
- of
- {ok, Profile} ->
- finish({ok, normalize_auth(Auth), normalize_profile(Profile)}, Req, Opts);
- _ ->
- finish({error, noprofile}, Req, Opts)
- catch _:_ ->
- finish({error, noprofile}, Req, Opts)
- end.
+get_access_token(Code, Opts) ->
+ {ok, Auth} = cowboy_request:post_for_json(
+ <<"https://oauth.vk.com/access_token">>, [
+ {code, Code},
+ {client_id, key(client_id, Opts)},
+ {client_secret, key(client_secret, Opts)},
+ {redirect_uri, key(callback_uri, Opts)},
+ {grant_type, <<"authorization_code">>}
+ ]),
+ {ok, [
+ {access_token, key(<<"access_token">>, Auth)},
+ {token_type, <<"Bearer">>},
+ {expires_in, key(<<"expires_in">>, Auth)}
+ ]}.
%%
-%% finalize application flow by calling callback handler
+%% extract info from user profile
%%
-finish(Status, Req, Opts) ->
- {M, F} = key(handler, Opts),
- M:F(Status, Req).
+get_user_profile(Auth, Opts) ->
+ {ok, Profiles} = cowboy_request:get_json(
+ <<"https://api.vk.com/method/users.get">>, [
+ {access_token, key(access_token, Auth)},
+ {fields, key(scope, Opts)}
+ ]),
+ % NB: provider returns list of data for uids; we need only the first
+ [Profile] = key(<<"response">>, Profiles),
+ {ok, [
+ {id, << "vkontakte:",
+ (list_to_binary(integer_to_list(key(<<"uid">>, Profile))))/binary >>},
+ {provider, <<"vkontakte">>},
+ % {email, key(<<"email">>, Profile)},
+ {name, << (key(<<"first_name">>, Profile))/binary, " ",
+ (key(<<"last_name">>, Profile))/binary >>},
+ {avatar, key(<<"photo">>, Profile)},
+ {gender, case key(<<"sex">>, Profile) of
+ 1 -> <<"female">>; _ -> <<"male">> end}
+ ]}.
%%
%%------------------------------------------------------------------------------
@@ -115,39 +79,3 @@ finish(Status, Req, Opts) ->
key(Key, List) ->
{_, Value} = lists:keyfind(Key, 1, List),
Value.
-
-%%
-%%------------------------------------------------------------------------------
-%% Provider details
-%%------------------------------------------------------------------------------
-%%
-
-authorize_url() ->
- <<"https://oauth.vk.com/authorize">>.
-
-token_url() ->
- <<"https://oauth.vk.com/access_token">>.
-
-profile_url() ->
- <<"https://api.vk.com/method/users.get">>.
-
-normalize_auth(Auth) ->
- [
- {access_token, key(<<"access_token">>, Auth)},
- {token_type, <<"Bearer">>},
- {expires_in, key(<<"expires_in">>, Auth)}
- ].
-
-normalize_profile(Raw0) ->
- % NB: provider returns list of data for uids; we need only the first
- [Raw] = key(<<"response">>, Raw0),
- [
- {id, << "vkontakte:",
- (list_to_binary(integer_to_list(key(<<"uid">>, Raw))))/binary >>},
- {provider, <<"vkontakte">>},
- % {email, key(<<"email">>, Raw)},
- {name, << (key(<<"first_name">>, Raw))/binary, " ",
- (key(<<"last_name">>, Raw))/binary >>},
- {avatar, key(<<"photo">>, Raw)},
- {gender, case key(<<"sex">>, Raw) of 1 -> <<"female">>; _ -> <<"male">> end}
- ].
View
161 src/cowboy_social_yandex.erl
@@ -5,107 +5,66 @@
-module(cowboy_social_yandex).
-author('Vladimir Dronnikov <dronnikov@gmail.com>').
--behaviour(cowboy_http_handler).
--export([init/3, terminate/3, handle/2]).
+-export([
+ get_authorize_url/1,
+ get_access_token/2,
+ get_user_profile/2
+ ]).
%%
%%------------------------------------------------------------------------------
%% OAUTH2 Application flow
%%------------------------------------------------------------------------------
%%
-init(_Transport, Req, Opts) ->
- % compose full redirect URI
- {SelfUri, Req2} = cowboy_req:host_url(Req),
- {ok, Req2, lists:keyreplace(callback_uri, 1, Opts,
- {callback_uri, << SelfUri/binary, (key(callback_uri, Opts))/binary >>})}.
-
-terminate(_Reason, _Req, _State) ->
- ok.
-
-handle(Req, Opts) ->
- % extract flow action name
- {Action, Req2} = cowboy_req:binding(action, Req),
- % perform flow action
- {ok, Req3} = handle_request(Action, Req2, Opts),
- {ok, Req3, undefined}.
-
-%%
-%% redirect to provider authorization page, expect it to redirect
-%% to our next handler
%%
-handle_request(<<"login">>, Req, Opts) ->
- AuthUrl = << (authorize_url())/binary, $?,
- (cowboy_request:urlencode([
- {<<"client_id">>, key(client_id, Opts)},
- {<<"redirect_uri">>, key(callback_uri, Opts)},
- {<<"response_type">>, <<"code">>},
- {<<"scope">>, key(scope, Opts)}
- ]))/binary >>,
- cowboy_req:reply(303, [{<<"location">>, AuthUrl}], <<>>, Req);
-
-%%
-%% provider redirected back to us with authorization code
+%% get URL of provider authorization page
%%
-handle_request(<<"callback">>, Req, Opts) ->
- case cowboy_req:qs_val(<<"code">>, Req) of
- {undefined, Req2} ->
- finish({error, nocode}, Req2, Opts);
- {Code, Req2} ->
- get_access_token(Code, Req2, Opts)
- end;
-
-%%
-%% catchall
-%%
-handle_request(_, Req, _) ->
- {ok, Req2} = cowboy_req:reply(404, [], <<>>, Req),
- {ok, Req2, undefined}.
+get_authorize_url(Opts) ->
+ << "https://oauth.yandex.ru/authorize", $?,
+ (cowboy_request:urlencode([
+ {client_id, key(client_id, Opts)},
+ {redirect_uri, key(callback_uri, Opts)},
+ {response_type, <<"code">>},
+ {scope, key(scope, Opts)}
+ ]))/binary >>.
%%
%% exchange authorization code for auth token
%%
-get_access_token(Code, Req, Opts) ->
- try cowboy_request:post_for_json(token_url(), [
- {<<"code">>, Code},
- {<<"client_id">>, key(client_id, Opts)},
- {<<"client_secret">>, key(client_secret, Opts)},
- {<<"redirect_uri">>, key(callback_uri, Opts)},
- {<<"grant_type">>, <<"authorization_code">>}
- ])
- of
- {ok, Auth} ->
- get_user_profile(Auth, Req, Opts);
- _ ->
- finish({error, notoken}, Req, Opts)
- catch _:_ ->
- finish({error, notoken}, Req, Opts)
- end.
-
-%%
-%% use auth token to extract info from user profile
-%%
-get_user_profile(Auth, Req, Opts) ->
- AccessToken = key(<<"access_token">>, Auth),
- try cowboy_request:get_json(profile_url(), [
- {<<"oauth_token">>, AccessToken},
- {<<"format">>, <<"json">>}
- ])
- of
- {ok, Profile} ->
- finish({ok, normalize_auth(Auth), normalize_profile(Profile)}, Req, Opts);
- _ ->
- finish({error, noprofile}, Req, Opts)
- catch _:_ ->
- finish({error, noprofile}, Req, Opts)
- end.
+get_access_token(Code, Opts) ->
+ {ok, Auth} = cowboy_request:post_for_json(
+ <<"https://oauth.yandex.ru/token">>, [
+ {code, Code},
+ {client_id, key(client_id, Opts)},
+ {client_secret, key(client_secret, Opts)},
+ {redirect_uri, key(callback_uri, Opts)},
+ {grant_type, <<"authorization_code">>}
+ ]),
+ {ok, [
+ {access_token, key(<<"access_token">>, Auth)},
+ {token_type, key(<<"token_type">>, Auth)},
+ {expires_in, 0}
+ ]}.
%%
-%% finalize application flow by calling callback handler
+%% extract info from user profile
%%
-finish(Status, Req, Opts) ->
- {M, F} = key(handler, Opts),
- M:F(Status, Req).
+get_user_profile(Auth, _Opts) ->
+ {ok, Profile} = cowboy_request:get_json(
+ <<"https://login.yandex.ru/info">>, [
+ {oauth_token, key(access_token, Auth)},
+ {format, <<"json">>}
+ ]),
+ {ok, [
+ {id, << "yandex:", (key(<<"id">>, Profile))/binary >>},
+ {provider, <<"yandex">>},
+ {email, key(<<"default_email">>, Profile)},
+ {name, key(<<"real_name">>, Profile)},
+ % {avatar, key(<<"picture">>, Profile)},
+ {gender, case key(<<"sex">>, Profile) of
+ 1 -> <<"female">>; _ -> <<"male">> end}
+ ]}.
%%
%%------------------------------------------------------------------------------
@@ -116,35 +75,3 @@ finish(Status, Req, Opts) ->
key(Key, List) ->
{_, Value} = lists:keyfind(Key, 1, List),
Value.
-
-%%
-%%------------------------------------------------------------------------------
-%% Provider details
-%%------------------------------------------------------------------------------
-%%
-
-authorize_url() ->
- <<"https://oauth.yandex.ru/authorize">>.
-
-token_url() ->
- <<"https://oauth.yandex.ru/token">>.
-
-profile_url() ->
- <<"https://login.yandex.ru/info">>.
-
-normalize_auth(Auth) ->
- [
- {access_token, key(<<"access_token">>, Auth)},
- {token_type, key(<<"token_type">>, Auth)},
- {expires_in, 0}
- ].
-
-normalize_profile(Raw) ->
- [
- {id, << "yandex:", (key(<<"id">>, Raw))/binary >>},
- {provider, <<"yandex">>},
- {email, key(<<"default_email">>, Raw)},
- {name, key(<<"real_name">>, Raw)},
- % {avatar, key(<<"picture">>, Raw)},
- {gender, case key(<<"sex">>, Raw) of 1 -> <<"female">>; _ -> <<"male">> end}
- ].

0 comments on commit e67610c

Please sign in to comment.