React: Best practice flow for SPA / Groups / Permission? (and how to get groups claim)

Hi guys

I’ve integrated okta with react through @okta/okta-react in my SPA.

The flow, which seems ridiculous and surely not the safest, is the following:

  1. Use the <Security> component from @okta/okta-react to set up okta’s config.
  2. In the actual app render conditionally through the use of { SecureRoute, ImplicitCallback }
  3. I set up a aws lambda function where I can check the authenticity of the access token after loggin which returns true or false according to the JWT validity

I have the following questions:

  1. Should this “check” of the JWT (throgh AWS lambda function) happen every time the user changes routes or should I cache the status somehow to avoid performing additional network calls?
  2. I want to restrict access to certain routes / components according to the role (which I guess in okta they are called Groups) what i am stupidly doing at the moment is: through an AWS lambda function, after the user is logged in, actually as soon as he is, I fetch its email from the locastorage that OKTA stores, send a request to my lambda that gets what groups it belongs to through OKTA api (/api/v1/users/${userId}/groups) and allow certain things according to the group’s id.

What flaws can you see? how can it be done better? what security measures need to be applied?

Thanks a lot for your help :pray:

Hi @VenomZzZ

It’s best to check the JWT locally when the user accesses a route.

The JWT token will not modify unless it’s refreshed or a new token is issued by Okta when the user accesses the /authorize endpoint, so, in case you encounter performance issues, you can set up a local cache, but be sure to cover any security scenario in which the cache can be used to access an endpoint after the JWT token expired or the user signed out.

You can define a “groups” claim in the authorization server to return the user’s groups. Once a new token is generated, on your end, you can check the groups claim in order to easily allow or deny access to certain routes. You can find out more details about this here.

1 Like

Hi @dragos

Thanks for taking your time to answer.

I have some questions still, apologies!

  1. You mention " in case you encounter performance issues, you can set up a local cache", in terms of what? Are we saying saving to localStorage / sessionStorage? and how? (in a conceptual level, not code-wise).
  2. From what I can read it seems I highly over-engineered the solution (Thank god as now it should be much more simple and straightforward, I am happy to know that!: joy:). You mention “It’s best to check the JWT locally” which I interpret as “client-side” not “server-side”, as I am using @okta/okta-react do you happen to know if that provides it and if so how would be the flow (also in a conceptual level, not asking for the actual code :pray:).
  3. I tried to get the claims of the group belonging to the logged in user but the only information I get back is the following:
    image
    which originates using the auth prop from the withAuth wrapper from @okta/okta-react

Other than the above queries/doubts my further questions are:

  1. Does this mean I don’t even need server side JWT verification like I was doing with aws’s lambdas? Since apparently somehow this can be done client-side?
  2. How can I limit components / routes to certain groups if the auth prop doesn’t come with what group the user belongs to? and even if it did, how would it be done properly (conceptually not pratically) as surely doing something like the following would be unsafe:
// Providing this is the auth prop response
const auth = {
  email: "email@domain.com",
  email_verified: true,
  family_name: "Macaluso",
  given_name: "Mel",
  locale: "en-US",
  name: "Mel Macaluso",
  preferred_username: "Mel Macaluso",
  sub: "12345abdefgh12345",
  updated_at: 1567003963,
  zoneinfo: "America/Los_Angeles",
  groups: ['admin', 'whatever'] // ie. adding this for the example, as I don't get a groups claim response in my auth prop (that's probably wrongly assuming there should be one)
}

const isAdmin = auth =>  auth.groups.includes('admin')

// in React 

{ isAdmin(auth) && 
  // Some protected component
}