-
Notifications
You must be signed in to change notification settings - Fork 5
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
What's the correct way to enforce that users are logged in when visiting an URL? #54
Comments
Hey, thanks for opening an issue :) This topic has a little bit that can be said about it, so I'll try to keep it short. A forewordIt's important to recognize the difference between authorization and authentication.
The Azure Identity platform does this like so:
So this package makes it possible for your web application to authorize itself to your app registration that you've defined in Azure AD. The latter uses the OpenID Connect protocol to do this. What does
|
def welcome(conn, _params) do | |
# Check if there's a session token | |
case conn |> get_session(:token) do | |
# If not, we redirect the user to the login page | |
nil -> | |
conn |> redirect(to: "/") | |
# If there's a token, we render the welcome page | |
token -> | |
{:ok, profile} = ElixirAuthMicrosoft.get_user_profile(token.access_token) | |
conn | |
|> put_view(AppWeb.PageView) | |
|> render(:welcome, %{profile: profile, logout_microsoft_url: ElixirAuthMicrosoft.generate_oauth_url_logout()}) | |
end | |
end |
We simply check if there's a token to control who gets to see this URL.
But wait. What if the token is expired/invalid?
Yes, access tokens in Azure AD are short-lived and need to be refreshed if they are expired to continue accessing Azure resources. There refresh tokens usually have a longer lifetime.
As it stands, this package does not have a way for you to refresh the token.
I'll open an issue for that.
If you see in our demo, we just assume the token is valid and let it crash if it's not.
{:ok, profile} = ElixirAuthMicrosoft.get_user_profile(token.access_token)
You can handle the scenario with your token if the request fails and handle this error (usually redirecting them to the login page suffices, forcing them to get a new valid access token).
Until we have provided you a way to refresh tokens, you can still use get_token/2
to keep your web app alive in case a request fails because your current token is invalid.
So, if a request fails because the token is invalid, use get_token/2
to get a new one :).
Here's an image of what a usual flow with tokens will look like with your web application. Our package makes it easy to get those tokens and return them to you.
We´ll eventually provide you with the tools to refresh the token,
but it's up to you to handle the error scenarios. If a request fails because the token is invalid, you need to refresh the token or get a new one (this is temporary while we implement a function to refresh the token) or force the user to go to the home page to log in.
To give you another perspective, msal
is Microsoft's official package for various frontend frameworks to make this process easy.
The way you're meant to check if a given person is already logged in and able to see the package is silently acquiring a token (which is checking if the token is valid) -> https://stackoverflow.com/questions/54346058/how-to-know-if-a-given-user-is-already-logged-in-with-msal
Alrighty. But what about roles? I want to allow a specific group of people to access a page and forbid others. How do I do that?
So far we've dealt with access tokens (used for authorization). The token returned by this package is the access token. ID Tokens can also be sent to the client application with claims with information about roles and permissions of the authorized user.
Microsoft's documentation are stellar. Read this for more information about the diff between tokens -> https://learn.microsoft.com/en-us/entra/identity-platform/security-tokens.
If you want to add roles and see them in your client application, you can control access at the App Registration-level by creating the roles there and making it so the roles are accessible in the token for you to see in the client application.
This goes a bit beyond the scope of what the package is now (though in the future it makes sense to have a an easy way to get the user's roles, even if you just need to JWT decode it) but to have role-based access on your application and have this information be returned on the access token, see https://learn.microsoft.com/en-us/answers/questions/1509291/(oidc)-configure-app-registration-to-return-roles.
TLDR;
Enforce the check on the mount/3
function to see if the session token exists. Redirect the user if to the login page if it's invalid/expired.
Thanks for the good and detailed answers, @LuchoTurtle & @ndrean! ❤️ |
Hi,
The gen.auth project has a
require_authenticated_user()
plug that can be used.I could not find anything here.
Can you guys please guide me on how the best security practices for implementing something similar?
The text was updated successfully, but these errors were encountered: