Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Token required even when not necessary #190

Closed
qortex opened this issue Aug 23, 2019 · 12 comments · Fixed by #195
Closed

Token required even when not necessary #190

qortex opened this issue Aug 23, 2019 · 12 comments · Fixed by #195
Milestone

Comments

@qortex
Copy link
Contributor

qortex commented Aug 23, 2019

The gem requires the token to be non-null (see this line), whereas it is useful to use the API (specifically those helpers) just to actually get a management token - and thus with a nil token to begin with.

I have this workaround for now, but that would be great to provide a canonical way (or maybe there is and I didn't think of it?):

# Get a brand new management token for this machine to machine app
Auth0Client.new(
        client_id: Rails.application.secrets.auth0_client_id,
        client_secret: Rails.application.secrets.auth0_api_mtom_client_secret,
        domain: Rails.application.secrets.auth0_domain,
        token: 'dummy-but-must-be-non-null-because-of-the-gem'
      ).api_token
@qortex
Copy link
Contributor Author

qortex commented Aug 23, 2019

Also discussed here: #86 - but added this issue anyway as a feature request.

@joshcanhelp
Copy link
Contributor

@MicMicMon - If you just need to use the Authentication API endpoints, you can require the gem and only pull in the component you need. Here is a quick example:

require 'auth0'

# SessionsController - login and logout controller.
# Handles the session creation in the app and Auth0 redirects.
class SessionsController < ApplicationController

  # Ruby SDK auth flow
  def new
    extend Auth0::Api::AuthenticationEndpoints
    options = {
      scope: 'openid email offline_access',
      state: SecureRandom.hex(16)
    }
    session[:auth0_state] = options[:state]
    redirect_to authorization_url(callback_url, options).to_s
  end
end

@qortex
Copy link
Contributor Author

qortex commented Aug 26, 2019

Ah yes, thanks for the idea.

Still, I'm not so keen on pulling chunks of code from a gem - that might change - inside my own code. Specifying state also smells like stuff that should be hidden from the library user IMO (and scope does not seem necessary in my use case).

Offering this hassle-free token creation through a Singleton-like class would be a very nice wrapper I think.

@joshcanhelp
Copy link
Contributor

I'm not so keen on pulling chunks of code from a gem - that might change - inside my own code.

Anything that's a public API, this in particular, will not change. We would expect someone to use the pieces they need.

Specifying state also smells like stuff that should be hidden from the library user IMO

This was just an example of how that module can be pulled in to use, I don't know what method you're trying to use there.

State can be random, like this, or it can contain actual state information (page to return to, shopping cart ID, etc) so it might actually be something that a developer would want to control.

Offering this hassle-free token creation through a Singleton-like class ...

I'm not sure I follow. You said you wanted to use this without a token ... am I missing something?

Thank you!

@qortex
Copy link
Contributor Author

qortex commented Aug 26, 2019

Yes ok I get it, it just pulls much more than I actually need into my own object - which I don't like that much. I prefer having a specific object outside that does not impact my own object signature.

Sorry I wasn't clear: I need a token once I get it. My need is:

  1. Get a Management API v2 token
  2. Use it with calls and such

Thus, a singleton object that achieves step 1 would be nice. That would replace mtom_api_token in the code I came up with:

  class Auth0ManagementAPI
    include Singleton

    def auth0_api
      @auth0_api ||= Auth0Client.new(
        client_id: Rails.application.secrets.auth0_client_id,
        domain: Rails.application.secrets.auth0_domain,
        token: mtom_api_token.access_token,
        api_version: 2
      )
    end

    # Return a fresh token for the Backend to interact with the Auth0 Management
    # API
    #
    # @return [ApiToken]
    def mtom_api_token
      Auth0Client.new(
        client_id: Rails.application.secrets.auth0_client_id,
        client_secret: Rails.application.secrets.auth0_api_mtom_client_secret,
        domain: Rails.application.secrets.auth0_domain,
        token: 'dummy-but-must-be-non-null-because-of-the-gem'
      ).api_token
    end

Then I simply use it (that's only then that I need the token):

    # Updates user metadata (the user typically can modify this metadata through
    # the UI).
    #
    # @param [String] user_id
    # @param [Hash] user_metadata
    #
    # @return [Hash] Updated user profile from Auth0
    def update_user_metadata(user_id, user_metadata)
      # Clears first, otherwise merges only
      auth0_api.patch_user(user_id, user_metadata: {})
      auth0_api.patch_user(user_id, user_metadata: user_metadata)
    end

Hope it's more clear that way.

It's definitely ok, I was just suggesting an improvement for the gem API - or maybe I don't know some classic pattern that you normally use in that case. Including the gem code inside my methods seems anti-pattern to me but I could well be wrong.

@joshcanhelp
Copy link
Contributor

I'm not clear why you're calling the api_token method on your own here. The token that's automatically retrieved when you don't pass one in will have all the permissions that your application is authorized for. I don't understand why your update_user_metadata method requires you to know the access token.

@qortex
Copy link
Contributor Author

qortex commented Aug 27, 2019

There must be something I don't understand. What do you mean by "the token that's automatically retrieved"?

If I replace my auth0_api with what I understand from your message:

def auth0_api
      @auth0_api ||= Auth0Client.new(
        client_id: Rails.application.secrets.auth0_client_id,
        domain: Rails.application.secrets.auth0_domain,
        # token: mtom_api_token.access_token,
        api_version: 2
      )
    end

I sure get this: Auth0::InvalidCredentials (Must supply a valid API token) (which makes sense to me), the gem doesn't automatically generate a token.

That's why I generate a token in the first place, following the instructions here.

What am I missing here?
Thanks for your time!

@joshcanhelp
Copy link
Contributor

joshcanhelp commented Aug 27, 2019

Ah ... that exception is not indicating that you can include the client_secret in Auth0Client.new and it will call the api_token method for you. I'll make a note in the readme and adjust that exception message to be more clear.

Example:

# ...
    def auth0_api
        @auth0_api ||= Auth0Client.new(
            client_id: Rails.application.secrets.auth0_client_id,
            domain: Rails.application.secrets.auth0_domain,
            client_secret: Rails.application.secrets.auth0_client_secret,
            api_version: 2
        )
    end
# ...

I'll leave this open to make sure that gets done. Apologies for the gap in documentation here!

@qortex
Copy link
Contributor Author

qortex commented Aug 27, 2019

Awesome, thanks for the clarification!
Works like a charm indeed.
Nice.

(I leave it open for you to close when you're comfortable)

@joshcanhelp
Copy link
Contributor

@MicMicMon - Thanks again for the report here. Would you mind taking a quick look at the PR and see if those instructions would have helped you earlier in the process?

#195

joshcanhelp added a commit that referenced this issue Sep 3, 2019
@qortex
Copy link
Contributor Author

qortex commented Sep 4, 2019

Sorry, didn't look at it until now. That's great, it is now totally clear I think :)
Thanks for your attention.

@joshcanhelp joshcanhelp added this to the v4.9.0 milestone Sep 25, 2019
@CesarOliveira
Copy link

CesarOliveira commented May 21, 2021

@qortex and @joshcanhelp sorry to bring this up again.

I'm trying to use the start_passwordless_email_flow method, to do that I have to insatiate a new auth0_client

But when I do that with my client_id and client_secret for my application I got:

Auth0::AccessDenied (
 {
  "error":"unauthorized_client", 
  "error_description":"Grant type 'client_credentials' not allowed for the client.",
  "error_uri":"https://auth0.com/docs/clients/client-grant-types"
 }
)

But to use the start_passwordless_email_flow through the Auth0 API I don't need the Client Credentials enabled in the application.

So I have two options:

  1. Use the Machine to Machine credentials to generate a access_token and then create a new client with that token and the client_id of my application that the Client Credentials;

  2. Insatiate a client with the token empty like this:

      auth0_client = Auth0Client.new(
        client_id: ENV.fetch('AUTH0_CLIENT'),
        domain: ENV.fetch('AUTH0_DOMAIN'),
        token: '' # or 'anything in here lik sugested by qortex'
      )

My question is, there is a better way to do use the start_passwordless_email_flow that doesn’t require having a client_secret?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants