Thanks to everybody for answers, but it didn’t become clearer, let move step by step. )
I’ve read really much of docs, but still don’t understand conception standing behind Auth0 API service. Really need your kind help. ) Questions are marked bold.
Let’s go.
1. For authentication I will use React SDK. I wrap the whole my app in Auth0Provider
ReactDOM.render(
`<Router>`
`<Auth0Provider>`
`<App />`
`</Auth0Provider>`
`</Router>`,
`document.getElementById("root")`
);
App.js:
import React from "react";
import { withAuth0 } from "@auth0/auth0-react";
class App extends React.Component {
render(){
const { isAuthenticated } = this.props.auth0;
return '...';
}
}
export default withAuth0(App);
Now I can create HOC with withAuthenticationRequired()
inside - this I will use for protecting routes (<ProtectedRoute/>
). For UI elements (menu links, some sections, etc) I will create another HOC, name it <isAuthorized/>
and will use it. And that’s it. Very simple.
As you said, after authentication (using React SDK) I get access_token and id_token.
Access_token I should only use for API requests, I shouldn’t decode it and somehow use on client side - only API requests. Id_token - from the box I get basic profile information.
So, in example above I don’t need access_token at all, I forget about it, I just can use id_token to show something in Profile page.
Everything is correct here?
2. Now I need more precise access control, not just allow/deny. I use rule to add permissions and role to id_token and after that I get those permissions in this.props.auth0.user. And now In each component I need, I just do conditional rendering based on permissions of user which are accessable all over the app via provider.
First things first, I need conditional rendering of ui. For some single components I use HOC again, <Can/>
:
class Can extends React.Component {
render(){
const { user } = this.props.auth0;
const needPermission = this.props.needPermission;
if(user.permissions.includes(needPermission)){
// render component
}else {
// do not render component
}
}
}
For some base components like menu I use json list of that menu:
export const menuJson = [
{
name: "...",
permission: 'perm1',
baseUrl: "...",
subs: [
{
baseUrl: "...",
name: "...",
permission: "perm2",
},
],
//...
},
]
When I render it from list I use again "if(this.props.auth0.user.permissions.includes(menuPermissionFromList))"
and then render or not render it.
a) Is this correct way? Or first I should save user permissions in redux state and then use it. If so, when I should save it to redux store?
b) I have an extra headache. Now I need somehow to synchronize permissions in Auth0 side with those in my app. Let’s say somebody changed name of permission on Auth0 side, but in my menu generator I have old permission name, hence I will never see the menu rendered. How to solve that?
3. And finally, the most interesting. I have API. I’ve set in Auth0 settings adding permissions to access_token. I do request to my API from frontend, add access_token as Bearer in headers.
On server side in PHP I verify access_token, decode it and get permissions from there. I know that I can trust them as soon as token valid while permissions are inside of it.
I have middleware that checks every request. Each server side route has its own identifier (permission). I have one more list of permission’s names on server side. What I do in middleware: I get permissions for that endpoint (route) from permissions list, and check if it exists in user’s permissions from access_token. Yes - server answers to request, no - it gives back an error.
Where and how exactly do I need those scopes, claims, how Auth0 can help me. I suppose that I do much extra job that auth0 can handle instead of me.
And again I need somehow to sync already three lists of permissions names: auth0 side, my server side and my frontend. I guess it not like it should work.