I'm working on a SPA that is utilizing ADAL JS. After calling adalService.logOut(), the user is properly redirected to the microsoft oauth logout URL and logout happens just fine. However, the user is logged out of all Microsoft 365 sites and all other sites utilizing ADAL.
Is there a way to only the log the user out of this one site?
Unfortunately, the way the ADAL JS library works is just as you described. When the logout function is called it clears the entire cache. Per the Wiki :
https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki/Login-methods#logout
Logout
When the logout method is called, the library clears the
application cache in the browser storage and sends a logout request to
the Azure AD instance's logout endpoint.
authContext.logOut(); The default behavior is to redirect the user to
window.location.href after logout. If a postLogoutRedirectUri value is
set at the config time, the user will be redirected to that URI.
The only other way to logout manually. That would be, look through the cache yourself, and delete the information you're interested in deleting there. This would in a way "logout" the user, since you have removed access to the token.
Per the wiki's config Auth Context https://github.com/AzureAD/azure-activedirectory-library-for-js/wiki/Config-authentication-context:
cacheLocation - ADAL caches tokens in the browser storage which
defaults to 'sessionStorage'. You can set this to either
'localStorage' or 'sessionStorage'.
window.config = {
clientId: 'g075edef-0efa-453b-997b-de1337c29185',
cacheLocation: 'localStorage' // Default is sessionStorage
}; Tokens are accessible from JavaScript since ADAL.JS is using HTML5 browser storage. It is recommended to prompt users to login
again for important operations in your app. You should also protect
your site for XSS. Please check the article here:
https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
You can read further details about the other configurable options
here.
And for more information on accessing local storage, you can read up on it here : https://blog.logrocket.com/the-complete-guide-to-using-localstorage-in-javascript-apps-ba44edb53a36
And the MDN Web doc for storage can be found here : https://developer.mozilla.org/en-US/docs/Web/API/Storage
Related
I am using B2C custom policies.
I am using Web.TPEngine.Providers.SelfAssertedAttributeProvider documented here:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/self-asserted-technical-profile
The signin relying party of the custom policy is working well, except users won't get user/password challenge after a successful login. I guess the technical profile uses browser cookies like "x-ms-cpim-cache|o4wex_p_gejeeak6w_0" for domain b2clogin.com to remember a successful login for at least a browser session.
The Metadata "setting.enableRememberMe" is the default that is set to false.
I need to make sure users are challenged with user/pwd every tinme the signin relying party is called. Is there any way to disable the auto-login with the cookie cache?
Set the session management technical profile to SM-Noop on the sign in technical profile.
For JavaScript apps, this will break silent token calls for an access token.
Other option, for initial logins, send the query param prompt=login which will kill the cookies when the user arrives at B2C. This at least keeps silent token calls working for JS apps.
I'm new to using Azure Active Directory authentication with a Web API. Right now the login page on my Single Page Application simple directs the user to the Microsoft login page where they enter their credentials and then are redirected back to my SPA. Upon the redirect the access token is now part of the URL. Is it possible to get that token via JSON rather than part of the URL? Is that a security risk making the token visible to user like that? If there is no other way to get the token what's the best way of processing that? Should I read the URL and pull the token from there and then redirect the user again to the actual website?
You have to be mindful in implicit flow the token will still be maintained at the client site (local storage normally). So even if you are hiding the token from URL , you still will be storing at client side and that's one of things you have to manage in SPA. You will have to send token with every HTTP request to your web api to get that authenticated on that end.
In implicit flow tokens are shortlives and you can't issue refresh token for longer period of access. For this kind of flow you need to use official library (ADAL.js)
https://github.com/AzureAD/azure-activedirectory-library-for-js
More resources
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-implicit-grant-flow
You can use ADAL.js library to acquire the token. There is a pre defined function which you have to call after the Ad authentication or at the beginning check if you are logged in, you can use isauthenticated function to check if you have already logged in, and use getaccesstoken function to acquire the token after authentication.
I have separate UI web app from the API web app. Both registered as applications in B2C. I've enabled Azure App Service Authentication / Authorization (easy auth) on the UI web app, and configured the API web app to use JwtBearer middleware to authenticate calls to API.
This seems to work, but I have trouble getting scopes through to the API web app. I have published the scopes in the API app, and configured the UI app to have access to these scopes.
I've tried different login URL options, e.g., https://myUIapp.azurewebsites.net/.auth/login/aad?p=b2c_1a_mysigninpolicy&scope=openid+https://myb2ctenant.onmicrosoft.com/api/company.read&post_login_redirect_uri=/app
and ensured that the API apps "App ID URI" (in B2C app settings) is indeed "api", while the scope name is company.read. Still after successful authentication, when going to /.auth/me, I do not see the scope, I do see other claims just fine.
Where should I start looking into pointers on this?
UPDATE
I've determined how I end up in this situation, but it is still unclear why:
User authenticates starting with URL such as: https://login.microsoftonline.com/mydevb2c.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1A_signin&client_id=UIAPP_GUID&nonce=defaultNonce&redirect_uri=https%3A%2F%2FUIAPP.azurewebsites.net%2F.auth%2Flogin%2Faad%2Fcallback&scope=openid%20https%3A%2F%2Fmydevb2c.onmicrosoft.com%2Fapi%2Fcompany.write%20https%3A%2F%2Fmydevb2c.onmicrosoft.com%2Fapi%2Fcompany.read&response_type=id_token%20token&prompt=login
After successful authentication, user is redirected to https://UIAPP.azurewebsites.net/.auth/login/aad/callback, as defined, BUT is immediately redirected back to authentication system with default scope set "openid+profile+email", i.e. URL such as https://login.microsoftonline.com/mydevb2c.onmicrosoft.com/oauth2/v2.0/authorize?response_type=id_token&redirect_uri=https%3A%2F%2FUIAPP.azurewebsites.net%2F.auth%2Flogin%2Faad%2Fcallback&client_id=UIAPP_GUID&scope=openid+profile+email&response_mode=form_post&p=b2c_1a_signinsuomifi&nonce=somenonce&state=redir%3D%252Fapp
If I take the access_token from the first callback to /.auth/login/aad/callback it contains the requested scopes, but second authentication callback obviously doesn't as it requests default scope set.
Do I perhaps need to start the easy auth login process via .auth/login/aad in order for it to accept the callback as well?
UPDATE 2
Yes, need to start the process via .auth/login/aad: when using login URL such as https://myUIapp.azurewebsites.net/.auth/login/aad?p=B2C_1A_signin&redirect_uri=https%3A%2F%2FmyUIapp.azurewebsites.net%2F.auth%2Flogin%2Faad%2Fcallback&scope=openid%20https%3A%2F%2Fmydevb2c.onmicrosoft.com%2Fapi%2Fcompany.write%20https%3A%2F%2Fmydevb2c.onmicrosoft.com%2Fapi%2Fcompany.read&response_type=id_token%20token&prompt=login&post_login_redirect_uri=/app removes the second authentication redirect.
The question now is, why do I only see the id_token in .auth/me and not the access_token that is clearly returned to the .auth/login/aad/callback? And ultimately: how come using the access_token as Bearer token, I still cannot query the easy auth secured API, but get error You do not have permission to view this directory or page.? I have followed steps in Azure client app accessing Azure api secured by AD.
If I switch off easy auth, and use the JwtBearer middleware in my API, it works fine.
My website has AAD authentication enabled and it works fine when we try to access the home page.
But if I am accessing html pages directly, it is not prompting for authentication. Am I missing any setting to enable authentication for all the pages?
Usually you have to set up your pages to request the user to be authenticated before it loads.
Here is me solving this problem with Python Flask:
Refresh Tokens for Azure AD V2 Applications in Flask
Now, in order to invoke this code at the right time, I need to create
a view decorator, and Flask has a sample for almost exactly what we
want to do here: a login required decorator.
Basically, we add this decorator to any view where we expect the user
to be signed in. If the user has no token, we will redirect them to
the login page. If they have an expired token and a refresh token, we
will use the refresh token to get a new access token. Otherwise, if
the token is present and valid, we simply let the view load.
This same concept is available out of the box using .Net: active-directory-dotnet-graphapi-web
You can find in the README of this sample the following:
If you want the user to be required to sign-in before they can see any
page of the app, then in the HomeController, decorate the
HomeController class with the [Authorize] attribute. If you leave this
out, the user will be able to see the home page of the app without
having to sign-in first, and can click the sign-in link on that page
to get signed in.
I've scoured the api docs, as well as StackOverflow, and I've yet to find the answer to my question. And it is possible I'm misunderstanding how the system works.
Here's the scenario our client wants:
User logs into our website
At which point we authenticate the user in our system, and One Login via the api.
After the user logs into our dashboard, they can click an link and be redirected to their third party analytics app due to the fact that I've created a new session with One Login.
Here are the steps I've completed.
I've successfully received an access token via --> https://developers.onelogin.com/api-docs/1/oauth20-tokens/generate-tokens
I've successfully used the access token to generate a session login token via --> https://developers.onelogin.com/api-docs/1/users/create-session-login-token
I've successfully used the session login token to create a new session.
I'm receiving the proper cookies from One Login after making the create new session request, and - at that point - if I enter the URL onelogin.com/login, I am taken directly to the dashboard.
At this point I know I'm properly authenticated with One Login. However, I'm not sure how to directly access a third party app from a link on our website.
Thanks.
Two ways:
If the app supports SP-initiated SAML, just navigate the user to the application and it'll do the whole SAML flow- App redirects to OneLogin - OL authenticates user (because you have a session) --- redirects SAML to app
Use the launch endpoint - You can create a URL to an app by using this format: https://app.onelogin.com/launch/{app-id}. For example, you can provide a link to an app like this:
Time Reporting
Details on that endpoint can be found here: https://developers.onelogin.com/api-docs/1/embed-apps/get-apps-to-embed-for-a-user
Take note that you're probably going to want to use the optional flag that makes sure to redirect to your login page, not OL's if you've built a login facade.