Help on a Google OAuth login working example? (I tried with multi_auth, it work with Github, but not with Google)

Hi, Can anyone help on give me a Google OAuth2 login working example? only email address is required.

I tried with multi_auth shard, but failed with a message:


The caller does not have permission to request “people/me”. Request requires one of the following scopes: [profile].


backtrace:

 GET /multi_auth/google/callback?code=4%2F0AVMBsJjvssA-eqjJQ-8EXtIeOy23ZmYMe4Iid9q4loqw7L1JL8KHVnHZn_Q-yTxEYxwpXQ&scope=email+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&authuser=0&prompt=none
  ▸  MultiAuth::Exception
      The caller does not have permission to request "people/me". Request requires one of the following scopes: [profile].
     Backtrace
      lib/multi_auth/src/multi_auth/providers/google.cr:87:15 in 'build_user'
      lib/multi_auth/src/multi_auth/providers/google.cr:59:5 in 'user'
      lib/multi_auth/src/multi_auth/engine.cr:30:5 in 'user'
      /src/actions/sign_ups/oauth/callback.cr:4:3 in 'action_call_body'
      /src/actions/sign_ups/oauth/callback.cr:4:3 in 'call'
      lib/lucky/src/lucky/renderable.cr:130:16 in 'perform_action'
      lib/lucky/src/lucky/route_handler.cr:10:7 in 'call'
      Crystal/share/crystal/src/http/server/handler.cr:30:7 in 'call_next'
      lib/lucky/src/lucky/remote_ip_handler.cr:26:5 in 'call'
      Crystal/share/crystal/src/http/server/handler.cr:30:7 in 'call_next'
      lib/lucky/src/lucky/error_handler.cr:15:5 in 'call'
      Crystal/share/crystal/src/http/server/handler.cr:30:7 in 'call_next'
      lib/lucky/src/lucky/log_handler.cr:34:9 in 'call'
      Crystal/share/crystal/src/http/server/handler.cr:30:7 in 'call_next'
      lib/lucky/src/lucky/http_method_override_handler.cr:11:5 in 'call'
      Crystal/share/crystal/src/http/server/handler.cr:30:7 in 'call_next'
      lib/lucky/src/lucky/force_ssl_handler.cr:37:7 in 'call'
      Crystal/share/crystal/src/http/server/handler.cr:30:7 in 'call_next'
      lib/lucky/src/lucky/request_id_handler.cr:24:5 in 'call'
      Crystal/share/crystal/src/http/server/request_processor.cr:51:11 in 'process'
      Crystal/share/crystal/src/http/server.cr:521:5 in 'handle_client'
      Crystal/share/crystal/src/http/server.cr:451:5 in '->'
      Crystal/share/crystal/src/fiber.cr:170:11 in 'run'
      Crystal/share/crystal/src/fiber.cr:105:3 in '->'

My source code is here

I create a issue there too.

Thanks

I think the error message is pretty clear. You need to require the “profile” scope in your request, but your code only requests the “email” scope.

Change

authorize_uri = MultiAuth.make(provider, redirect_uri).authorize_uri(scope: "email")

to

authorize_uri = MultiAuth.make(provider, redirect_uri).authorize_uri(scope: "profile")

will probably solve this problem.

1 Like

Thanks, after change to scope: "profile", previous error gone, but can’t get email, but name and image get return back, any idea?

 @access_token=
  #<OAuth2::AccessToken::Bearer:0x74e4ebe07d40
   @access_token=
    "ya29.a0AS3H6Ny4c5P8Mu1RBx9w1KJWAzHagmG-sMdtrOguD_iXK-kzmb9gbuGtU_CyYYBiv5qZhAbV0aUg4DrcxJPcS9Er_8Cb46FbGKVrA0175",
   @expires_in=3599,
   @extra=
    {"id_token" =>
      "\"eyJhbGciOiJSUzI1NiIsImtpZCI6Ijg4MjUwM2E1ZmQ1NmU5ZjczNGRmYmE1YzUwZDdiZjQ4ZGIyODRhZTkiLCJ0eXAixMzk5cTgxZTZjamtuNzUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI0NjMwNjcxNTU0OTQtcGFmMGd0MzI2ZjZn9oYXNoIjoiVWdXaGMyclBIamZYdUdIbF9KS3cwUSIsIm5hbWUiOiJCaWxseSBaaGVuZyIsInBpY3R1cmUiOiJodHRwczovL2xoMy5i1jIiwiZ2l2ZW5fbmFtZSI6IkJpbGx5IiwiZmFtaWx5X25hbWUiOiJaaGVuZyIsImlhdCI6MTc1MTM4MDA5MSwiZXhwIjoxNzUxMz1SvyhExm2Lg63z6TcVJECfEM0-MHWZtW7oEaUlDHCuidTYsQP_IoorhjlNR7dSmiSL-occOHKwn1ivwL62bW7gvl7SUjRIwO65DQO
Y_MP2iBEU8xfZOt46hs-H8kgZlleyA\""},
   @refresh_token=nil,
   @scope="https://www.googleapis.com/auth/userinfo.profile">,
 @description=nil,
 @email=nil,
 @first_name="Billy",
 @image=
  "https://lh3.googleusercontent.com/a/ACg8ocJUI5wfm-dplGh4GCZbCbcVDytOfKmq2av5JgbnEjZSKGp9IIw=s100",
 @last_name="Zheng",
 @location=nil,
 @name="Billy Zheng",
 @nickname=nil,
 @phone=nil,
 @provider="google",
 @raw_json=
  "{\n" +
  "  \"resourceName\": \"people/111593971251064096723\",\n" +
  "  \"etag\": \"%EhQBAgMFBgkKCxAUFxkiLjU3PT4/QBoEAQIFByIMUDJrdnlLYWlGRVU9\",\n" +
  "  \"names\": [\n" +
  "    {\n" +
  "      \"metadata\": {\n" +
  "        \"primary\": true,\n" +
  "        \"source\": {\n" +
  "          \"type\": \"PROFILE\",\n" +
  "          \"id\": \"111593971251064096723\"\n" +
  "        },\n" +
  "        \"sourcePrimary\": true\n" +
  "      },\n" +
  "      \"displayName\": \"Billy Zheng\",\n" +
  "      \"familyName\": \"Zheng\",\n" +
  "      \"givenName\": \"Billy\",\n" +
  "      \"displayNameLastFirst\": \"Zheng, Billy\",\n" +
  "      \"unstructuredName\": \"Billy Zheng\"\n" +
  "    }\n" +
  "  ],\n" +

Oops, change to scope = "profile email" work, I have no idea … I hate GDD(Guess Driven Development)

When doing a request to an OAuth-protected resource you can specify any number of scopes (separated by a space). That is in the OAuth standard: RFC 6749: The OAuth 2.0 Authorization Framework

What scopes that are needed to access a particular piece of information is up to the provider, but in this case you could probably find some hints in the OpenID Connect standard (OIDC). Here is a list of standard scopes for OIDC: https://auth0.com/docs/get-started/apis/scopes/openid-connect-scopes#standard-claims

1 Like