Authorization for the nuxt frontend

If I understand the issue correctly (as described on github, cmty.app and on dev.to (link in next post)), the keycloak endpoint accepts a client_secret parameter. The problem is that the nuxt oath2 scheme doesn’t send the client_secret. The current solution is that the sirixdb server holds the client secret, and forwards the browser to keycloak together with the client_secret.

So nuxt connects to the sirixdb server, which redirects to keycloak, which authenticates and redirects back to nuxt.

The propsed solution is to define a custom keycloak schme to forward client_secret as well. So nuxt will redirect directly to keycloak, without the sirixdb server in the middle.

@johannes if I have this correct, I can work on an implementation.

1 Like

Only two links per post allowed for new users, so here is the dev.to link.

1 Like

Yes, correct summary. In our case we do not necessarily need the SirixDB HTTP-Server between Node.js and Keycloak. For SPAs the SirixDB HTTP-Server is needed to do the authentication (and in that case it’s using the parameters specified in the config file), but currently our front-end is running in universal (also recommended Nuxt.js mode) and besides Nuxt.js per default does not send a client_secret it should work without the SirixDB HTTP-server as a proxy. The SirixDB HTTP-server then will validate the JWT tokens, which have to be sent in the Authentication HTTP-header as a Bearer token without ever communicating with Keycloak.

I apologize, but I don’t quite follow your thinking. There are three services: sirixdb, keycloak, and nuxt server. If the nuxt frontend runs completely in the browser, that merely means that it takes over the tasks of the nuxt server, correct? Why should the function of the sirixdb server change?

The client_secret has to be kept secret. However, there’s a way to not need a server and still don’t switch to the implicit OAuth2 flow:

1 Like

@johannes thanks for that link. Very helpful.

On another note, it turns out that we don’t need a whole new scheme - we can just replace this:

@Component
export default class Login extends Vue {
  private login(): void {
    this.$auth.loginWith('keycloak')   
  }
}

with this:

export default class Login extends Vue {
  private login(): void {
    this.$auth.loginWith('keycloak', {params: {client_id: process.env.client_id, client_secret: process.env.client_secret} }) 
  }
}

and the nuxt configuration:

auth: {
    strategies: {
      keycloak: {
	_scheme: 'oauth2',
	authorization_endpoint: 'auth/realms/sirixdb/protocol/openid-connect/auth',
	userinfo_endpoint: false,
	access_type: 'offline',
	access_token_endpoint: '/auth/realms/sirixdb/protocol/openid-connect/token',
	response_type: 'code',
	token_type: 'Bearer',
  token_key: 'access_token',
      },
    },
    redirect: {
      login: '/login',
      callback: '/callback',
      home: '/'
    },
  },
  env: {
    client_id: 'sirix',
    client_secret: 'ab00e459-3196-4110-923b-e58d71bd4c88'
  },
  router: {
    middleware: ['auth']
  },
  proxy: {
    '/auth/': {
      target: 'http://localhost:8080',
      pathRewrite: {'^/api/': ''}
    }
  }

And it seems to work, until I get a
We're sorry... An error occurred, please login again through your application.
from the /auth/realms/sirixdb/login-actions/authenticate endpoint. I’m stuck on that.

1 Like

I think it has something to do with Scope: AUTH_CODE not being the headers. Not sure though.

1 Like

@mosheduminer maybe the refresh token somehow is not stored by Nuxt.js? At least I think the auth middleware should automatically redirect to /login, so it’s a bit strange.

Perhaps. I’ll look into it later.

I don’t think we need a particular scope. If nothing is sent I’m pretty sure Keycloak issues a token, which has all access rights.

One idea I have would be looking if on the redirect_uri (/callback route/page) the refresh token has the right name or if Keycloak sends it at all: https://github.com/nuxt-community/auth-module/blob/e21de05cdf65deea67dbc1215ccb08673a7232bb/lib/schemes/oauth2.js#L141

This is super strange.

I couldn’t get the proxy stuff running, so

  auth: {
    strategies: {
      keycloak: {
	_scheme: 'oauth2',
	authorization_endpoint: 'http://localhost:8080/auth/realms/sirixdb/protocol/openid-connect/auth',
	userinfo_endpoint: false,
	access_type: 'offline',
	access_token_endpoint: 'http://localhost:8080/auth/realms/sirixdb/protocol/openid-connect/token',
	response_type: 'code',
	token_type: 'Bearer',
        token_key: 'access_token',
        grant_type: 'refresh_token'
      },
    },
    redirect: {
      login: '/login',
      callback: '/callback',
      home: '/'
    },
  },
  env: {
    client_id: 'sirix',
    client_secret: '2e54cfdf-909b-47ca-b385-4c44886f04f0'
  },
  router: {
    middleware: ['auth']
  }

But now regardless of what I specify in the allowed Web Origins in Keycloak (http://localhost:3005 without the slash at the end for instance), I’m getting the CORS error again:

POST http://localhost:8080/auth/realms/sirixdb/protocol/openid-connect/token 400 (Bad Request)
callback?state=nDsZilYezQMD4IDUVe86B&session_state=184be869-7c6c-4775-8379-c4ccf2d9410c&code=3d6306a0-f6db-4c80-beab-ee40e7f104b1.184be869-7c6c-4775-8379-c4ccf2d9410c.10456029-a4ea-4493-b6ab-70807876bc9f:1 Access to XMLHttpRequest at 'http://localhost:8080/auth/realms/sirixdb/protocol/openid-connect/token' from origin 'http://localhost:3005' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource

Ah, now I got the problem. Have a look at this code from nuxt.js auth module (OAuth2): https://github.com/nuxt-community/auth-module/blob/dev/lib/schemes/oauth2.js#L156

There the client_secret is still not sent. The real error message is this: {“error”:“unauthorized_client”,“error_description”:“Client secret not provided in request”}

What was the problem with the proxy? The proxy is what keeps the CORS error from happening.

1 Like

Hmm, it didn’t rewrite to the other host:port… so it was http://localhost:3005 instead of http://localhost:8080. Couldn’t get it to run somehow. But maybe you can give me your whole config file?

What’s bothering me a bit is that the Nuxt.js authorization guys give zero support in the forum and are also not replying on Twitter… :frowning:

1 Like

I didn’t change the config other than what I posted. However, calling 3005 is expected behavior, the browser calls the the proxy (the nuxt server at 3005) which in turn forwards the request (according to the config I posted, any request whose path begins with /auth/) to 8080. So it should work despite calling 3005.

:frowning: :man_shrugging:

So, it seems it didn’t forward the request :frowning: It couldn’t find http://localhost:3500/auth/realms/sirixdb/protocol/openid-connect/auth, but I’ll try again at home :slight_smile:

Can you confirm, that the Keycloak server doesn’t respond with a 400 HTTP-Errorcode if you look into the request against the /token endpoint?

I can fix this, when I resend the request with the client_secret. However, then it tells me, that the form doesn’t have a grant_type parameter. This is when I manually set the URL to http://localhost:8080/auth/realms/sirixdb/protocol/openid-connect/token instead of http://localhost:3005. When I’m just using the URL http://localhost:3005/auth/realms/sirixdb/protocol/openid-connect/token I’m getting a 400 error without a response from the Keycloak server somehow!? Hmm!