@@ -6,21 +6,31 @@ defmodule Ueberauth.Strategy.Google do
66 use Ueberauth.Strategy ,
77 uid_field: :sub ,
88 default_scope: "email" ,
9- hd: nil ,
10- userinfo_endpoint: "https://www.googleapis.com/oauth2/v3/userinfo"
9+ hd: nil
1110
12- alias Ueberauth.Auth.Info
13- alias Ueberauth.Auth.Credentials
1411 alias Ueberauth.Auth.Extra
1512
13+ @ session_key "ueberauth_strategy_google"
14+
1615 @ doc """
1716 Handles initial request for Google authentication.
1817 """
1918 def handle_request! ( conn ) do
20- scopes = conn . params [ "scope" ] || option ( conn , :default_scope )
21-
22- params =
23- [ scope: scopes ]
19+ scopes =
20+ String . split (
21+ conn . params [ "scope" ] || option ( conn , :default_scope ) ,
22+ " "
23+ )
24+
25+ scopes =
26+ if "openid" in scopes do
27+ scopes
28+ else
29+ [ "openid" ] ++ scopes
30+ end
31+
32+ authorization_params =
33+ [ ]
2434 |> with_optional ( :hd , conn )
2535 |> with_optional ( :prompt , conn )
2636 |> with_optional ( :access_type , conn )
@@ -30,33 +40,39 @@ defmodule Ueberauth.Strategy.Google do
3040 |> with_param ( :prompt , conn )
3141 |> with_param ( :login_hint , conn )
3242 |> with_param ( :hl , conn )
33- |> with_state_param ( conn )
3443
35- opts = oauth_client_options_from_conn ( conn )
36- redirect! ( conn , Ueberauth.Strategy.Google.OAuth . authorize_url! ( params , opts ) )
44+ opts =
45+ conn
46+ |> options_from_conn ( )
47+ |> Map . put ( :scopes , scopes )
48+ |> Map . put ( :authorization_params , Map . new ( authorization_params ) )
49+
50+ case UeberauthOidcc.Request . handle_request ( opts , conn ) do
51+ { :ok , conn } ->
52+ conn
53+
54+ { :error , conn , reason } ->
55+ UeberauthOidcc.Error . set_described_error ( conn , reason , "error" )
56+ end
3757 end
3858
3959 @ doc """
4060 Handles the callback from Google.
4161 """
42- def handle_callback! ( % Plug.Conn { params: % { "code" => code } } = conn ) do
43- params = [ code: code ]
44- opts = oauth_client_options_from_conn ( conn )
62+ def handle_callback! ( % Plug.Conn { } = conn ) do
63+ opts = options_from_conn ( conn )
4564
46- case Ueberauth.Strategy.Google.OAuth . get_access_token ( params , opts ) do
47- { :ok , token } ->
48- fetch_user ( conn , token )
65+ case UeberauthOidcc.Callback . handle_callback ( opts , conn ) do
66+ { :ok , conn , token , userinfo } ->
67+ conn
68+ |> put_private ( :google_token , token )
69+ |> put_private ( :google_user , userinfo )
4970
50- { :error , { error_code , error_description } } ->
51- set_errors! ( conn , [ error ( error_code , error_description ) ] )
71+ { :error , conn , reason } ->
72+ UeberauthOidcc.Error . set_described_error ( conn , reason , "error" )
5273 end
5374 end
5475
55- @ doc false
56- def handle_callback! ( conn ) do
57- set_errors! ( conn , [ error ( "missing_code" , "No code received" ) ] )
58- end
59-
6076 @ doc false
6177 def handle_cleanup! ( conn ) do
6278 conn
@@ -81,87 +97,49 @@ defmodule Ueberauth.Strategy.Google do
8197 """
8298 def credentials ( conn ) do
8399 token = conn . private . google_token
84- scope_string = token . other_params [ "scope" ] || ""
85- scopes = String . split ( scope_string , " " )
86-
87- % Credentials {
88- expires: ! ! token . expires_at ,
89- expires_at: token . expires_at ,
90- scopes: scopes ,
91- token_type: Map . get ( token , :token_type ) ,
92- refresh_token: token . refresh_token ,
93- token: token . access_token
94- }
100+ credentials = UeberauthOidcc.Auth . credentials ( token )
101+ % { credentials | other: % { } }
95102 end
96103
97104 @ doc """
98105 Fetches the fields to populate the info section of the `Ueberauth.Auth` struct.
99106 """
100107 def info ( conn ) do
108+ token = conn . private . google_token
101109 user = conn . private . google_user
102110
103- % Info {
104- email: user [ "email" ] ,
105- first_name: user [ "given_name" ] ,
106- image: user [ "picture" ] ,
107- last_name: user [ "family_name" ] ,
108- name: user [ "name" ] ,
109- birthday: user [ "birthday" ] ,
110- urls: % {
111- profile: user [ "profile" ] ,
112- website: user [ "hd" ]
113- }
111+ info = UeberauthOidcc.Auth . info ( token , user )
112+
113+ % {
114+ info
115+ | birthday: info . birthday || user [ "birthday" ] ,
116+ urls: Map . put_new ( info . urls , :website , user [ "hd" ] )
114117 }
115118 end
116119
117120 @ doc """
118121 Stores the raw information (including the token) obtained from the google callback.
119122 """
120123 def extra ( conn ) do
124+ creds = credentials ( conn )
125+
126+ # create a struct with the same format as the old token, even if we don't depend on OAuth2
127+ google_token = % {
128+ __struct__: OAuth2.AccessToken ,
129+ access_token: creds . token ,
130+ refresh_token: creds . refresh_token ,
131+ expires_at: creds . expires_at ,
132+ token_type: "Bearer"
133+ }
134+
121135 % Extra {
122136 raw_info: % {
123- token: conn . private . google_token ,
137+ token: google_token ,
124138 user: conn . private . google_user
125139 }
126140 }
127141 end
128142
129- defp fetch_user ( conn , token ) do
130- conn = put_private ( conn , :google_token , token )
131-
132- # userinfo_endpoint from https://accounts.google.com/.well-known/openid-configuration
133- # the userinfo_endpoint may be overridden in options when necessary.
134- resp = Ueberauth.Strategy.Google.OAuth . get ( token , get_userinfo_endpoint ( conn ) )
135-
136- case resp do
137- { :ok , % OAuth2.Response { status_code: 401 , body: _body } } ->
138- set_errors! ( conn , [ error ( "token" , "unauthorized" ) ] )
139-
140- { :ok , % OAuth2.Response { status_code: status_code , body: user } }
141- when status_code in 200 .. 399 ->
142- put_private ( conn , :google_user , user )
143-
144- { :error , % OAuth2.Response { status_code: status_code } } ->
145- set_errors! ( conn , [ error ( "OAuth2" , status_code ) ] )
146-
147- { :error , % OAuth2.Error { reason: reason } } ->
148- set_errors! ( conn , [ error ( "OAuth2" , reason ) ] )
149- end
150- end
151-
152- defp get_userinfo_endpoint ( conn ) do
153- case option ( conn , :userinfo_endpoint ) do
154- { :system , varname , default } ->
155- System . get_env ( varname ) || default
156-
157- { :system , varname } ->
158- System . get_env ( varname ) || Keyword . get ( default_options ( ) , :userinfo_endpoint )
159-
160- other ->
161- other
162- end
163- end
164-
165143 defp with_param ( opts , key , conn ) do
166144 if value = conn . params [ to_string ( key ) ] , do: Keyword . put ( opts , key , value ) , else: opts
167145 end
@@ -170,18 +148,45 @@ defmodule Ueberauth.Strategy.Google do
170148 if option ( conn , key ) , do: Keyword . put ( opts , key , option ( conn , key ) ) , else: opts
171149 end
172150
173- defp oauth_client_options_from_conn ( conn ) do
174- base_options = [ redirect_uri: callback_url ( conn ) ]
175- request_options = conn . private [ :ueberauth_request_options ] . options
151+ defp options_from_conn ( conn ) do
152+ base_options = [
153+ issuer: UeberauthGoogle.ProviderConfiguration ,
154+ userinfo: true ,
155+ session_key: @ session_key
156+ ]
176157
177- case { request_options [ :client_id ] , request_options [ :client_secret ] } do
178- { nil , _ } -> base_options
179- { _ , nil } -> base_options
180- { id , secret } -> [ client_id: id , client_secret: secret ] ++ base_options
181- end
158+ request_options = conn . private [ :ueberauth_request_options ] . options
159+ oauth_options = Application . get_env ( :ueberauth , Ueberauth.Strategy.Google.OAuth ) || [ ]
160+
161+ [
162+ base_options ,
163+ request_options ,
164+ oauth_options
165+ ]
166+ |> UeberauthOidcc.Config . merge_and_expand_configuration ( )
167+ |> generate_client_secret ( )
168+ |> fix_token_url ( )
182169 end
183170
184171 defp option ( conn , key ) do
185172 Keyword . get ( options ( conn ) , key , Keyword . get ( default_options ( ) , key ) )
186173 end
174+
175+ defp generate_client_secret ( % { client_secret: { mod , fun } } = opts ) do
176+ Map . put ( opts , :client_secret , apply ( mod , fun , [ Keyword . new ( opts ) ] ) )
177+ end
178+
179+ defp generate_client_secret ( opts ) do
180+ opts
181+ end
182+
183+ defp fix_token_url ( % { token_url: token_endpoint } = opts ) do
184+ opts
185+ |> Map . put ( :token_endpoint , token_endpoint )
186+ |> Map . delete ( :token_url )
187+ end
188+
189+ defp fix_token_url ( opts ) do
190+ opts
191+ end
187192end
0 commit comments