peburrows / goth Goto Github PK
View Code? Open in Web Editor NEWElixir package for Oauth authentication via Google Cloud APIs
Home Page: http://hexdocs.pm/goth
License: MIT License
Elixir package for Oauth authentication via Google Cloud APIs
Home Page: http://hexdocs.pm/goth
License: MIT License
Unsure what is missing here.
Looking for advice.
Deps
{:goth, "~> 1.3-rc"},
{:hackney, "~> 1.17"},
{:google_api_compute, "~> 0.34.0"}
application.ex
def start(_type, _args) do
credentials =
"GOOGLE_APPLICATION_CREDENTIALS_JSON"
|> System.fetch_env!()
|> Jason.decode!()
source = {:service_account, credentials, []}
...
{Goth, name: Toolbox.Goth, source: source}
Error Trace
** (Mix) Could not start application toolbox: Toolbox.Application.start(:normal, []) returned an error: shutdown: failed to start child: Goth.Server
** (EXIT) an exception was raised:
** (ArgumentError) argument error: [[], {:jose_jws, {:jose_jws_alg_rsa_pkcs1_v1_5, :RS256}, :undefined, %{"typ" => "JWT"}}, %{"aud" => "https://oauth2.googleapis.com/token,", "exp" => 1616384563, "iat" => 1616380963, "iss" => "[email protected],", "scope" => "https://www.googleapis.com/auth/cloud-platform"}]
(jose 1.11.1) src/jwt/jose_jwt.erl:184: :jose_jwt.sign/3
(goth 1.3.0-rc.0) lib/goth/token.ex:200: Goth.Token.jwt/2
(goth 1.3.0-rc.0) lib/goth/token.ex:149: Goth.Token.request/1
(goth 1.3.0-rc.0) lib/goth/token.ex:109: Goth.Token.fetch/1
(goth 1.3.0-rc.0) lib/goth/server.ex:49: Goth.Server.init/1
```
The Goth's source
parameters has a field scope
. That is a string but actually it can contain multiple scopes separated by a single space. The code below works:
source = {
:service_account, credentials,
scope: "https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/gmail.compose",
sub: "[email protected]"
}
children = [{Goth, name: :my_goth, source: source}]
{:ok, _} = Supervisor.start_link(children, strategy: :one_for_one)
It would be nice if the scope
becomes scopes
and expects a list of strings. Because
Hey! When requesting for the access token of a google service account JSON file I have in my project I get a strange bearer token construction. With this behaviour the token still works, but it's strange to just give this output.
def get_authorization_token(scope \\ default_scopes()) do
case Token.for_scope(scope) do
{:ok, %Goth.Token{token: token, type: type}} ->
{:ok, {"authorization", "#{type} #{token}"}}
_ ->
{:error, :authorization_code}
end
end
When calling the function, I get the following:
iex(1)> Google.Auth.get_authorization_token
{:ok, {"authorization", "Bearer ya29.c.Kq{token}bE...{an absurd repetition of dots π}..."}}
Today I was having strange issues with a container running on GKE, when trying to upload an image using https://github.com/martide/arc_gcs every request was throwing this error:
** (MatchError) no match of right hand side value: {:error, %HTTPoison.Error{id: nil, reason: :connect_timeout}}
(goth) lib/goth/client.ex:53: Goth.Client.get_access_token/2
(goth) lib/goth/token.ex:94: Goth.Token.retrieve_and_store!/1
lib/arc/storage/gcs.ex:79: Arc.Storage.GCS.get_token/0
lib/arc/storage/gcs.ex:113: Arc.Storage.GCS.default_headers/0
lib/arc/storage/gcs.ex:61: Arc.Storage.GCS.do_put/4
(elixir) lib/task/supervised.ex:85: Task.Supervised.do_apply/2
(elixir) lib/task/supervised.ex:36: Task.Supervised.reply/5
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
is the timeout for httpoison on goth configurable? Also, it seems pretty strange that I got timeouts since it was a request within google datacenter, after restarting the container everything worked correctly
When calling Goth.Token.for_scope/1
, I see
** (MatchError) no match of right hand side value:
{:error, %HTTPoison.Error{id: nil, reason: {:options, {:sslv3,
{:versions, [:"tlsv1.2", :"tlsv1.1", :tlsv1, :sslv3]}}}}}
Is this a misconfiguration on my system (Elixir 1.10.4, Linux Mint 20 x86_64)?
Goth.Client.check_metadata_scope checks to see if the requested scope is declared with the service account token provided by the metadata service, and errors out if not. But I don't think a straight string comparison does the right thing, because some scopes imply others.
For example, I'm trying to run an app in an App Engine VM. By default, GAE instance service accounts don't provide the https://www.googleapis.com/auth/datastore
scope explicitly, but do instead provide https://www.googleapis.com/auth/cloud-platform
which is kind of a catch-all that includes datastore. Since Diplomat requests https://www.googleapis.com/auth/datastore
specifically, it's failing the check_metadata_scope test, even though the scope is actually valid.
I suspect we should just omit the check. If the metadata-provided token has insufficient scopes, the downstream services will check for us.
Are there any plans to support the target_audience
claim as described in the IAP docs ?
goth depends on:
json_web_token depends on:
This makes the dependency graph unresolvable. The workaround is to set "override: true" for the poison version.
Referring to this section:
https://github.com/peburrows/goth/blob/master/README.md#L26-L29
In the README it says to pass in the path from system ENV, but looking function Goth.Config.load_and_init/1
, it is triggering Goth.Config.from_json/1
function.
https://github.com/peburrows/goth/blob/master/lib/goth/config.ex#L121-L127
It will produce not valid json format from Jason.
I think it is missing a step. If :json
is a path, it should load the json file before decoding with Jason. Or, it should be limited to just json string when using this config option?
mix.exs deps looks like this:
{:goth, "~> 1.2", config: :goth, json: "file.json" |> File.read!},
I also ran export GOOGLE_APP_CREDENTIALS=... already. What's going on?
** (Mix) Could not start application goth: Goth.start(:normal, []) returned an error: shutdown: failed to start child: Goth.Config
** (EXIT) an exception was raised:
** (RuntimeError) Failed to retrieve project data from GCE internal metadata service.
Either you haven't configured your GCP credentials, you aren't running on GCE, or both.
Please see README.md for instructions on configuring your credentials.
(goth 1.2.0) lib/goth/config.ex:182: Goth.Config.determine_project_id/2
(goth 1.2.0) lib/goth/config.ex:73: anonymous fn/2 in Goth.Config.load_and_init/1
(elixir 1.10.2) lib/enum.ex:1400: anonymous fn/3 in Enum.map/2
(stdlib 3.12.1) maps.erl:232: :maps.fold_1/3
(elixir 1.10.2) lib/enum.ex:2127: Enum.map/2
(goth 1.2.0) lib/goth/config.ex:71: Goth.Config.load_and_init/1
(stdlib 3.12.1) gen_server.erl:374: :gen_server.init_it/2
(stdlib 3.12.1) gen_server.erl:342: :gen_server.init_it/6
(stdlib 3.12.1) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
I switch to 1.3-rc
and it didn't work as 1.2
- {:goth, "~> 1.2.0"},
+ {:goth, "~> 1.3-rc"},
+ {:hackney, "~> 1.17"},
def start(_type, _args) do
credentials =
"GOOGLE_APPLICATION_CREDENTIALS" |> System.fetch_env!() |> File.read!() |> Jason.decode!()
scopes = ["https://www.googleapis.com/auth/datastore"]
source =
{:service_account, credentials, scopes: scopes}
children = [
{Goth, name: OurApp.Goth, source: source},
]
end
- {:ok, token} = Goth.Token.for_scope("https://www.googleapis.com/auth/datastore")
+ {:ok, token} = Goth.fetch(QonverApi.Goth)
When you run the command gcloud auth application-default-credentials login
the credentials are deposited at ~/.config/gcloud/application_default_credentials.json
.
This behavior doesn't seem to be documented in the Application Default Credentials documentation. However, many of the google supported libraries seem to identify credentials at this location (such as the python api).
It would be great if this library would also support his credentials location as part of the ADC lookup procedure.
I am getting results from the token request that is not parseable by Goth.
dev.exs:
config :goth,
json: "./xxxxxxxxxxx.json" |> File.read!
Code:
{:ok, token} = Token.for_scope("[email protected]")
returns:
** (ArithmeticError) bad argument in arithmetic expression
:erlang.+(1558592257, nil)
lib/goth/token.ex:117: Goth.Token.from_response_json/3
Problem seems to be in token.ex where it is trying to parse the attributes of the returned JSON. When I inspect the JSON returned it looks like a JWT token.
%{
"id_token" => "eyJhbGciOiJSUzI1NiIsImtpZCI6IjJjM2ZhYzE2YjczZmM4NDhkNDI2ZDVhMjI1YWM4MmJjMWMwMmFlZmQiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhdWQiOiJzbmFwcHktc3RhY2tlci01NThAYXBwc3BvdC5nc2VydmljZWFjY291bnQuY29tIiwiYXpwIjoic25hcHB5LXN0YWNrZXItNTU4QGFwcHNwb3QuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInN1YiI6IjEwNTA4OTc0ODgyNzQxNjE1NjU5NSIsImVtYWlsIjoic25hcHB5LXN0YWNrZXItNTU4QGFwcHNwb3QuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJpYXQiOjE1NTg1OTIyNTcsImV4cCI6MTU1ODU5NTg1N30.Wbzpj8X5g11pfTSeFOFqqkq8HmDzO3ojVL2GXYkP4oeDACg5GlFXCxw9mJPzLs0tQgkPXPKgunJKaAlTDzSXUUa4mbz9eCKz_uFm5S90lbwfYN0zGd0wkawjXYk6pMsgAU4K9Mg4R6p4u-PdVYxBzUBKQLpirN3MmLGvlLnss6-e12njHaVjN-PVJE9RiGsq66UdPlJTz4phQH6jARD9kgvSMV6ufrlscS93_09A3JMJqKjUi1LtlduRcWEftmsze1fQ4LfAiKbJTh7IBF6h4kJQCFUkG9-yI6YO9CpFLTKAInODB-RtApSeWU9F71ibqNpax_r4UhO_oEOeG4SAqg"
}
When I decode that assuming it is a JWT token, I get:
%{
"aud" => "[email protected]",
"azp" => "[email protected]",
"email" => "[email protected]",
"email_verified" => true,
"exp" => 1558596508,
"iat" => 1558592908,
"iss" => "https://accounts.google.com",
"sub" => "105089748827416156595"
}
None of those attributes are the ones expected by goth (access_token, token_type, expires_in).
Am I doing something wrong?
I am trying to use Goth + Waffle + waffle_gcs on Google App Engine using the default service account, and without providing the credentials in any way through custom environmental variable or JSON file. I am using Goth 1.2, i.e. the version before redesign at the moment.
Things seem to work just fine, including uploading attachments to cloud storage, but waffle / waffle_gcs seem to fail on generating signed URL to display / download uploaded files.
I have pin pointed the error to this line over here:
https://github.com/tyler-eon/waffle_gcs/blob/master/lib/waffle/storage/google/url_v2.ex#L82
And indeed, when I try to manually execute Goth.Config.get(:client_email)
I am getting :error
instead of OK tuple.
I am not entirely sure where the problem is, and if that's a Goth or waffle_gcs issue so please excuse me if this is a wrong place to ask. Do you have any ideas what's wrong with my set up and if I do have to do a custom set up and give up using default service accoutnt?
Is there a way to use different service account (possibly related to completely different projects)?
In the context of my current project, I need to call the Google APIs as a dozen different users in order to retrieve data from all my projects. Does the feature already exist?
Thanks.
Just a suggestion, currently goth uses 0.11, but the latest httpoison version is 1.0. I followed here all the way from https://github.com/sashaafm/gcloudex :)
Hello.
I'm using goth with elixir-google-api.
Goth works in my dev environment, but It does not work in my remote docker container.
** (MatchError) no match of right hand side value: {:error, %HTTPoison.Error{id: nil, reason: {:tls_alert, {:unknown_ca, 'TLS client: In state wait_cert_cr at ssl_handshake.erl:1895 generated CLIENT ALERT: Fatal - Unknown CA\n'}}}}
It occurs when I run this function.
{:ok, token} = Goth.Token.for_scope("https://www.googleapis.com/auth/cloud-platform")
Is there any hints to resolve it?
The type specification for the method Token.for_scope/1
specifies that it can return an :error
atom but it never does
In which cases can Token.for_scope/1
return an error? If it can actually can return an error then it should be handled, if not, the type specification should be removed
I transferred the GCP JSON credentials to another system.
{:ok, token} = Goth.Token.for_scope("https://www.googleapis.com/auth/cloud-platform")
Currently we infer project ID only from the Compute Engine metadata server (if available).
While I don't think there's a documented recipe for how to infer the project, the way that we have for application default credentials, there are some common practices being used (still somewhat inconsistently) by the auth libraries for other languages:
GOOGLE_CLOUD_PROJECT
(and the legacy GCLOUD_PROJECT
) environment variables, which are set in the App Engine Flexible Environment, and also often set by applications. (example from nodejs)DEVSHELL_PROJECT_ID
environment variable, which is set by Google Cloud Shell. (example from ruby)I can provide a pull request if you agree with these.
I'm using {:ok, goth} = Goth.Token.for_scope("https://www.googleapis.com/auth/devstorage.full_control")
But i seen a bug. Please help me
** (exit) an exception was raised:
** (UndefinedFunctionError) function :crypto.mpint/1 is undefined or private
(crypto) :crypto.mpint(19687873431742193920055970243130294467124206658682087298983794038798216955530975915146333586732314900700035611611045789143545904247799428447896803420118324471667046274052296120024954651561469080093219328190691149886440049200669636272584661976356321702914680136369124759272732574776698998044554776915282967732669956832401458331945711479325049514685797410840542208523089896590986235120222095570675226125560522026179882816977851505433864383972624362893774956738669017687990725035030542706539434148824251987312659383648295704127681204473207295376320651645980971185202320992998884262991006767805018245431366563316696488933)
elixir -v
Erlang/OTP 22 [erts-10.7] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe] [dtrace]
Elixir 1.10.2 (compiled with Erlang/OTP 22)
iex(1)> Goth.Token.for_scope("https://www.googleapis.com/auth/pubsub")
[info] TLS :client: In state :certify at ssl_handshake.erl:377 generated CLIENT ALERT: Fatal - Internal Error
- {:unexpected_error, :undef}
{:error,
%HTTPoison.Error{
id: nil,
reason: {:tls_alert,
{:internal_error,
'TLS client: In state certify at ssl_handshake.erl:377 generated CLIENT ALERT: Fatal - Internal Error\n {unexpected_error,undef}'}}
}}
Installation instructions still show ~> 0.0.1
Hey, For working with development env goth
works smooth as butter, but while deploying the app in kubernetes I already have Kubernetes Service Account
binded to Google Service Account
however is there a way to directly pass the Kubernetes Service Account identity to goth instead of JSON file?
As in production from security perspective using JSON file is not a good practise.
It would help a lot with testing if we could have a setting to ignore the TokenStore, forcing it to always get a new one.
Or, if there was a TokenStore.clear
method we could at least create a test helper to clear the cache before specific tests, making them predictable.
I'm using bypass to simulate several conditions (token created, error creating token etc) and there comes a point where the token I created for a given scope is already cached from previous tests, affecting their predictability.
As mentioned in #77, Goth should support ADC. Additionally Goth should Just Workβ’οΈ out of the box without needing to provide an explicit source in the case that default credentials exist. I propose we mirror the google-auth Python library that I suspect most GCP users have experience with. They have the order of defaults to use documented here. I propose we mirror this order where Goth supports the auth methods (it's unclear the GAE method is supported).
I am trying to use GCP system credentials in Google Cloud and am receiving an error ** (UndefinedFunctionError) function Joken.Signer.create/2 is undefined (module Joken.Signer is not available)
Hi there,
Is there any way to make it possible to accept a Base 64 encoded version of the JSON auth credentials? The huge JSON string is a bit unwieldy.
Goth is structured so it reads configuration at start and then attempts to verify credentials. This makes it very difficult for it to work in environments where configuration is loaded dynamically. Take a look at this article for best practices to avoid this issue and other cascading ones: https://michal.muskala.eu/2017/07/30/configuring-elixir-libraries.html
I need to be able to disable all Goth functionality for local development and use it only in production. There's really no clean way to do this in Goth currently
I noticed that although version 1.2.0 has been released, it hasn't been tagged yet. While GitHub provides a nice visual diff for the changes which have been merged since v1.1.0, this will change as soon as new commits get added.
Would you please tag the commit which was built and pushed to Hex.
Goth.Token.for_scope/1
has a typespec{:ok, t}
, but I believe should be {:ok, t} | {:error, any()}
as it will return HTTPoison errors.
Not the biggest of deals, but it makes downstream dialyzer a bit noisy.
Thanks for your work on this library. Its been super useful!
This is most likely an issue on my end, but the solution is not obvious to me.
I previously used Goth 1.2 without any issues. After upgrading to 1.3.0-rc.3 and configuring it exactly as the readme says, I have the following problem.
When developing, if my laptop suspends for longer than the token expiration window, when resuming, Goth will attempt to get a token from Google using the already expired cached refresh token. Google replies with a 400, which causes Goth to raise and fail. However, when the supervisor restarts it, Goth does not ask for a new token using the service account credentials, but instead uses the stale refresh token again. This repeats every second until I restart the app.
At least that's how it appears to me.
Here's what I see in my logs. Formatted for legibility:
[error] GenServer {Goth.Registry, Readyroom.Goth} terminating
** (RuntimeError) too many failed attempts to refresh, last error:
%RuntimeError{
message: "unexpected status 400 from Google\n\n{
\"error\":\"invalid_grant\",
\"error_description\":\"Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your iat and exp values in the JWT claim.\"}\n"
}
(goth 1.3.0-rc.3) lib/goth/server.ex:80: Goth.Server.handle_info/2
(stdlib 3.16.1) gen_server.erl:695: :gen_server.try_dispatch/4
(stdlib 3.16.1) gen_server.erl:771: :gen_server.handle_msg/6
(stdlib 3.16.1) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
Last message: :refresh
State: %Goth.Server{
http_client: {Goth.HTTPClient.Hackney, %Goth.HTTPClient.Hackney{default_opts: []}},
name: Readyroom.Goth,
refresh_before: 300,
retries: 1,
retry_after: 1000,
source: {
:service_account, %{
"auth_provider_x509_cert_url" => "https://www.googleapis.com/oauth2/v1/certs",
"auth_uri" => "https://accounts.google.com/o/oauth2/auth",
"client_email" => "<elided>.iam.gserviceaccount.com",
"client_id" => "<elided>",
"client_x509_cert_url" => "https://www.googleapis.com/robot/v1/metadata/x509/<elided>.iam.gserviceaccount.com",
"private_key" => "-----BEGIN PRIVATE KEY-----\n<elided>\n-----END PRIVATE KEY-----\n",
"private_key_id" => "<elided>",
"project_id" => "<elided>",
"token_uri" => "https://oauth2.googleapis.com/token",
"type" => "service_account"
},
[scopes: ["https://www.googleapis.com/auth/cloud-platform"]]
}
}
Any assistance you can give would be appreciated.
Hello is this project dead? I'm trying to get a token for Cloud Storage but it doesn't seem to work:
{:ok, token} = Token.for_scope("https://www.googleapis.com/storage/v1/b")
** (MatchError) no match of right hand side value: :error
(goth) lib/goth/client.ex:35: Goth.Client.jwt/2
(goth) lib/goth/client.ex:10: Goth.Client.get_access_token/1
(goth) lib/goth/token.ex:66: Goth.Token.retrieve_and_store!/1
Is there a way to get an access token for a Google Cloud Function invocation via Goth? This is the code example, but I would prefer to rely on Goth instead:
cloud_function_url = "https://<REGION>-<PROJECT_ID>.cloudfunctions.net/<FUNCTION_NAME>"
{:ok, client_email} = Goth.Config.get(:client_email)
{:ok, private_key} = Goth.Config.get(:private_key)
signer = Joken.Signer.create("RS256", %{"pem" => private_key})
claims = %{
target_audience: cloud_function_url,
aud: "https://www.googleapis.com/oauth2/v4/token",
iss: client_email,
sub: client_email,
iat: :os.system_time(:seconds),
exp: :os.system_time(:seconds) + 10
}
{:ok, jwt} = Joken.Signer.sign(claims, signer)
google_api_url = "https://www.googleapis.com/oauth2/v4/token"
body =
{:form,
[
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
assertion: jwt
]}
headers = [{"Content-Type", "application/x-www-form-urlencoded"}]
result = HTTPoison.post(google_api_url, body, headers)
{:ok, %{status_code: 200, body: "" <> _ = body}} = result
{:ok, %{"id_token" => google_token}} = Jason.decode(body)
Thank you!
{:ok, token} = Goth.Token.for_scope({
...(1)> "[email protected]",
...(1)> "https://www.googleapis.com/auth/cloud-platform.read-only"})
** (MatchError) no match of right hand side value: :error
lib/goth/client.ex:44: Goth.Client.get_access_token/2
lib/goth/token.ex:150: Goth.Token.retrieve_and_store!/2
Im using the JSON file from GCP.
Could authentication/credential logic be skipped when $PUBSUB_EMULATOR_HOST is defined, so that just the project_id key is included in the Goth config module? Other google cloud clients also use that environment variable: https://cloud.google.com/pubsub/docs/emulator#accessing_environment_variables
Alternatively, the Kane pubsub library could be updated to use a mock Goth module in that case.
I was running an elixir app in docker against the emulator locally, and was running into an nxdomain
error when goth tried to fetch metadata before creating a topic. It took a while for me to figure out that goth uses the default location of application credentials on my machine to authenticate when :json is absent (https://github.com/peburrows/goth/blob/master/lib/goth/config.ex#L142), which was why the library worked locally but not on the docker container.
If emulator support won't be added here, it may be helpful to handle that error with a more informative message ("Credentials missing" etc.)
I'd like to call Gmail API with a service account key. Goth 1.2.0
has Goth.Token.for_scope/2
, where I can put the user ID in the second argument. But how can I achieve the same with Goth 1.3.0
?
Here is my code
def start_goth do
info("Starting goth")
credentials = Application.fetch_env!(:my_app, :gmail_token_file)
|> Path.expand()
|> File.read!()
|> Jason.decode!()
source = {:service_account, credentials, scope: "https://www.googleapis.com/auth/gmail.readonly"}
children = [{Goth, name: :my_goth, source: source}]
{:ok, _} = Supervisor.start_link(children, strategy: :one_for_one)
{:ok, token} = Goth.fetch(:my_goth)
conn = GoogleApi.Gmail.V1.Connection.new(token.token)
warn("token: #{inspect(token)}")
GoogleApi.Gmail.V1.Api.Users.gmail_users_messages_list(conn, "[email protected]", [maxResults: 10])
end
Goth version: 1.3-rc
When passing hackney without default_opts
as http_client
to Goth.Token.fetch
it breaks:
This does not work:
iex(3)> Goth.Token.fetch(%{source: {:metadata, []}, http_client: {Goth.HTTPClient.Hackney, []}})
** (ArgumentError) you attempted to apply :default_opts on []. If you are using apply/3, make sure the module is an atom. If you are using the dot syntax, such as map.field or module.function(), make sure the left side of the dot is an atom or a map
:erlang.apply([], :default_opts, [])
(goth 1.3.0-rc.3) lib/goth/http_client/hackney.ex:40: Goth.HTTPClient.Hackney.request/6
(goth 1.3.0-rc.3) lib/goth/token.ex:175: Goth.Token.request/1
This does work:
Goth.Token.fetch(%{source: {:metadata, []}, http_client: {Goth.HTTPClient.Hackney, %{default_opts: []}}})
Hi, I'd like to propose a Goth redesign that replaces the global, application env-based, configuration with a more direct approach. This will in general give more control to the users (e.g. when exactly Goth starts, how it's configured, etc) and in particular it will solve one of the long standing issues of supporting multiple credentials. The new design is also more scalable as it replaces a single GenServer with process-less lookups. Finally, I'd like to also make the http client swappable and reduce the number of dependencies.
Here's the plan I have in mind:
Goth.start_link/1
, Goth.fetch/1
, Goth.Token.fetch/1
I decided to keep the existing code as is (with @moduledoc false
, @doc false
, etc) to not break existing clients.
I'll send the PR for the first two items shortly.
I want to set up a test environment where I can run tests without credentials for goth to start. In my test.exs
I have:
config :goth,
disabled: true
When I run mix test
with this, I get an error:
** (Mix) Could not start application goth: Goth.start(:normal, []) returned an error: shutdown: failed to start child: Goth.Config
** (EXIT) an exception was raised:
** (RuntimeError) Failed to retrieve project data from GCE internal metadata service.
Either you haven't configured your GCP credentials, you aren't running on GCE, or both.
Please see README.md for instructions on configuring your credentials.
(goth) lib/goth/config.ex:139: Goth.Config.determine_project_id/2
(goth) lib/goth/config.ex:60: Goth.Config.init/1
(stdlib) gen_server.erl:374: :gen_server.init_it/2
(stdlib) gen_server.erl:342: :gen_server.init_it/6
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
When I substitute in the valid credentials for the prod environment, the tests are able to run as expected. Is my config for disabling goth incorrect?
This only appears to have cropped up recently but there is now an error when retrieving the token from Goth.
Goth.Client.get_access_token("https://www.googleapis.com/auth/pubsub")
=NOTICE REPORT==== 21-May-2020::17:29:31.899288 ===
TLS client: In state certify at tls_connection.erl:1164 generated CLIENT ALERT: Fatal - Handshake Failure - malformed_handshake_data
{:error,
%HTTPoison.Error{
id: nil,
reason: {:tls_alert,
{:handshake_failure,
'received CLIENT ALERT: Fatal - Handshake Failure - malformed_handshake_data'}}
}}
I am using erlang 22.0 along with Elixir 1.9.4 and 1.10.3.
There is a server that is using elrang 23 as a base and that also has the same issue.
Getting this warning message on compilation -
warning: function init/1 required by behaviour GenServer is not implemented (in module Goth.TokenStore).
We will inject a default implementation for now:
def init(args) do
{:ok, args}
end
But you want to define your own implementation that converts the arguments given to GenServer.start_link/3 to the server state
Hello, thanks for goth it's great. I have a question.
I made a lib that has goth as a dependancy. Let's call it gcp_secret_provider. I want to use gcp_secret_provider in another app, App A.
I have configured goth in gcp_secret_provider, and App A shouldn't know about Goth at all. But currently if I include gcp_secret_provider in App A, app A will crash on start up in :dev
env or :test
env because goth is incorrectly configured.
In gcp_secret_provider I have this in config/config.exs
config(:goth, json: ~S({
"project_id": "PROJECT_ID",
"private_key": "MOCK_KEY",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/my_lovely_app.iam.gserviceaccount.com"
}))
So I would expect when I start App A that the above config would be given to goth and it would all be fine. Do you know why it's not?
Is it something to do with when Goth's genserver(s) get started?
Thanks for any help.
On these lines you pattern match for (only) {:ok, response}
:
Line 66 in fa32be1
Line 87 in fa32be1
I see quite a few exceptions like this after switching networks and/or waking my Mac:
** (MatchError) no match of right hand side value: {:error, %HTTPoison.Error{id: nil, reason: :nxdomain}}
(goth) lib/goth/client.ex:66: Goth.Client.get_access_token/3
(goth) lib/goth/token.ex:100: Goth.Token.retrieve_and_store!/2
...
Is it a deliberate choice that these kinds of errors should cause exceptions, or have you just not gotten around to handling more error cases gracefully? If itβs the latter, would you be open to a PR?
I have been trying to auth with Google with Goth.Token.for_scope/1
, and would get this error:
** (MatchError) no match of right hand side value: {:error, %HTTPoison.Error{id: nil, reason: :nxdomain}}
(goth) lib/goth/client.ex:64: Goth.Client.get_access_token/3
(goth) lib/goth/token.ex:151: Goth.Token.retrieve_and_store!/2
Looking in to the code base, I found it is trying to call http://metadata.google.internal
, hence the :nxdomain
error. I feel I missed something during the setup, but can't figure it out. How should I understand this error?
Thanks
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.