How to use the Auth0.js library in a custom hosted login page?

We created an SPA with our own look and feel for the login part (NOT based on Lock as we needed more customization than that), we wanted OIDC conformance (because it is future proof) and the ability to renew tokens (for security purpose, our tokens have a short life time, so we have to renew them)

In order to be able to renew tokens, we had to split our SPA code to be served for the login part on Auth0 server, by injecting part of our code (CSS, JS) in a Custom Hosted Login Page (HLP). We get the config from a global we create from @@config@@we then inject the relevant part of it in our original Auth0.js code. This part, serving our own page in a Custom HLP, works as expected :rocket:

We at first used the webAuth.client.login on the HLP in order to login, but we would not get back the needed cookies to have the token renewal to work. Reverse engineering the default custom HLP (which allows us to login, renew tokens and logout properly with the exact same configuration, just not our own custom HLP yet) showed us that we needed to hit a different endpoint.

After a process of trials and errors, we saw that the call to actually send is webauth.redirect.loginWithCredentials, plus we were pretty sure, and still are, that it was the good API to call, because it is quite explicitly written in the documentation:

However, using webauth.redirect.loginWithCredentials is the correct choice for use in the Hosted Login Page, and is the only way to have SSO cookies set for your users who login using the Hosted Login Page.

We don’t use (yet) the SSO cookies for a real SSO, but we assume this is what allows us to renew the tokens using the default custom HLP

At this point we then got the:

access_denied: Password login is disabled for clients using externally hosted login pages with oidc_conformant flag set.

Having read somewhere in the docs that the auth0/lock lib available on the HLP is a little bit different, we changed our webpack config to just wrap the lib served from the auth0 CDN, to load it the same way it is done in the default Custom hosted login page template.

However, we still had the same error :sob:

According to, this is probably a configuration issue (yet we do NOT use Lock and do NOT want to use it), but we are stuck now, what should we do?

There is now more than one template to choose from when you enable the HLP customization in your Dashboard. In particular, there’s a Custom Login Form template that shows the most common authentication methods using the Auth0.js library so if you haven’t check this yet it might be useful sample code.

As you mentioned, the most common cause for the error in question when you are within the HLP itself is some sort of incorrect configuration. The template mentioned above, after including the Auth0.js library and the necessary Object.assign polyfill initializes the library like this:

  var config = JSON.parse(

  var params = Object.assign({
    domain: config.auth0Domain,
    clientID: config.clientID,
    redirectUri: config.callbackURL,
    responseType: 'code'
  }, config.internalOptions);

  var webAuth = new auth0.WebAuth(params);

Besides the common options you would be already used to even when using it outside the HLP take particular note of the usage of config.internalOptions. When using Lock in the HLP failing to consider the internal options is the most common cause for the error so it’s worth a shot for you to review if you’re using a similar approach to initialize the Auth0.js library. If this does not end up solving, it may be easier to troubleshoot if you include the relevant parts as an update to the question.

We had these same general questions when we created our initial (custom) HLP, and IMO this is an area where Auth0 could make what is effectively the content of your post above @jmangelo1 easier to find in the general “here is how to create a custom HLP” documentation. Once you create an initial version, you say to yourself “hey, that was actually pretty easy”, but getting there can cause a few stumbles along the way.

Note: IE11 doesn’t like “Object.assign”, so to fix this, we implemented the following:

Object.keys(config.internalOptions).forEach(function (k) {
    params[k] = config.internalOptions[k];

Worked !
Auth0 documentation should probably be really more detailed on this I agree with @joe.tillotson

1 Like