I'm using OIDC Client in my angular application for authentication against identity server 4. Everything works fine until i hit sign out.
I've enabled monitor session (enabled by default) so that other browser can detect the sign out and i can log the user out in other tab of the same browser. When I sign out from one tab, the other tab makes a request to the identity server for silent refresh token and that get succeed. I'm expecting the other browser to signout as well. If i hit the F5 in the other tab then yes, it gets redirected to login again. but not automatically.
Update
to log out from other clients that share the same identity server frontChannel
, you can add an Iframe in your identity to notify your clients about the logout (oidc-client.js supports front-channel signout)
Front-channel server-side clients
To signout the user from the server-side client applications via the front-channel spec, the “logged out” page in IdentityServer must render an to notify the clients that the user has signed out. Clients that wish to be notified must have the FrontChannelLogoutUri configuration value set. IdentityServer tracks which clients the user has signed into, and provides an API called GetLogoutContextAsync on the IIdentityServerInteractionService (details). This API returns a LogoutRequest object with a SignOutIFrameUrl property that your logged out page must render into an .
Back-channel server-side clients
To signout the user from the server-side client applications via the back-channel spec, the SignOutIFrameUrl endpoint in IdentityServer will automatically trigger server-to-server invocation passing a signed sign-out request to the client. This means that even if there are no front-channel clients, the “logged out” page in IdentityServer must still render an to the SignOutIFrameUrl as described above. Clients that wish to be notified must have the BackChannelLogoutUri configuration value set.
Browser-based JavaScript clients
Given how the session management specification is designed, there is nothing special in IdentityServer that you need to do to notify these clients that the user has signed out. The clients, though, must perform monitoring on the check_session_iframe, and this is implemented by the oidc-client JavaScript library.
after that you can listen the event addUserSignedOut of oidc-client in all your clients and trigger signoutRedirect to logout your client
this._userManager.events.addUserSignedOut(() => {
this._userManager
.signoutRedirect()
.then(resp => {
console.log('Success');
})
.catch(err => {
console.log(err);
});
});
check this documentation for more details
Related
Consider that we have:
An SPA or a statically generated JAMStack website.
A REST API.
The website is being served with nignx that also reverse proxies to our API.
--
It is required that a user should be able to register/authenticate with an identity provider (say, Google) through the OpenID Connect protocol. For the sake of simplicity, let us assume that the user has already registered with our API.
Talking about authentication using OIDC, from what I have read on the subject, the steps you take are the following:
Register the application with the IdP and receive a client id and a secret.
When the user initiates a login (with Google) request on the API ('/api/loginWithGoogle') the API sets a state variable on the request session (to prevent CSRF) and redirects the user-agent to the IdP's login page.
At this page, the user enters their credentials and if they are correct, the IdP redirects the user to the callback URL on the API callback (/api/callback).
The request received on the callback has the state parameter (which we should verify with the one we set on the session previously) and a code parameter. We exchange the code for the identity token with the authorization server/IdP (we also receive access/refresh tokens from the auth server, which we discard for now because we do not want to access any APIs on the behalf of the user).
The identity token is parsed to verify user identity against our database (maybe an email).
Assume that the identity is verified.
-- The next part is what's giving me trouble --
The documentation that I have read advises that from here we redirect the user to a URL (e.g. the profile page)and start a login session between the user agent and the API. This is fine for this specific architecture (with both the SPA/static-site being hosted on the same domain).
But how does it scale?
Say I want to move from a session based flow to a JWT based flow (for authenticating to my API).
What if a mobile application comes into the picture? How can it leverage a similar SSO functionality from my API?
NOTE: I have read a little on the PKCE mechanism for SPAs (I assume it works for JAMStack as well) and native mobile apps, but from what I gather, it is an authorization mechanism that assumes that there is no back-end in place. I can not reconcile PKCE in an authentication context when an API is involved.
Usually this is done via the following components. By separating these concerns you can ensure that flows work well for all of your apps and APIs.
BACKEND FOR FRONTEND
This is a utility API to keep tokens for the SPA out of the browser and to supply the client secret to the token service.
WEB HOST
This serves unsecured static content for the SPA. It is possible to use the BFF to do this, though a separated component allows you to serve content via a content delivery network, which some companies prefer.
TOKEN SERVICE
This does the issuing of tokens for your apps and APIs. You could use Google initially, though a more complete solution is to use your own Authorization Server (AS). This is because you will not be able to control the contents of Google access tokens when authorizating in your own APIs.
SPA CLIENT
This interacts with the Backend for Frontend during OAuth and API calls. Cookies are sent from the browser and the backend forwards tokens to APIs.
MOBILE CLIENT
This interacts with the token service and uses tokens to call APIs directly, without using a Backend for Frontend.
BUSINESS APIs
These only ever receive JWT access tokens and do not deal with any cookie concerns. APIs can be hosted in any domain.
SCALING
In order for cookies to work properly, a separate instance of the Backend for Frontend must be deployed for each SPA, where each instance runs on the same parent domain as the SPA's web origin.
UPDATE - AS REQUESTED
The backend for frontend can be either a traditional web backend or an API. In the latter case CORS is used.
See this code example for an API driven approach. Any Authorization Server can be used as the token service. Following the tutorial may help you to see how the components fit together. SPA security is a difficult topic though.
We have a project where the client requests the use of their own Identity Provider, in this case, it is SalesForce.
We secure the application using IdentityServer 3 and have configured it that for this client (based on parameters) it will use SalesForce as the IDP.
For the web app, no problem, Identity Server redirects to the Sales Force login page and everything works great.
Now we have a mobile app to build and the client would like to avoid having a web login page and would rather have a nice polished login form built in the application. This means that we will have to use the Resource Owner flow.
Now, the users creds are on SalesForce side so how does that work and is this at all possible in IdentityServer 3 ?
I see 2 possibilities but I kind of like neither of them:
Send the auth call to IdentityServer which should detect that it is up to SalesForce to validate the user and forwards the request there. I think it is not good as I would rather avoid having my IdentityServer dealing with credentials that he should not even know
Send a first auth call to SalesForce to get some "id token" that would then allow me to send another auth call to IdentityServer which will then recognize the "id token" and release an access token.
That seems like a stretch and forces the app to know that there is an IDP which is none of its business.
Any idea?
I am trying to implement Single-Sign-Out procedure within my clients and Identity Provider (Identity Server 4). I managed to set correctly an Iframe page that gets rendered whenever a user logs out (either from the Identity Server itself or from a client). Such rendering triggers the call of the endsession endpoint, which is an internal mechanism of Identity Server that calls all the clients who have a BackChannelLogoutUri registered. My client receives the call from Identity Server (it's a POST call) but unfortunately the call is not authenticated.
This causes a redirect in my client due to a non authorized call.
At the same time I cannot really debug what's happening in this endsession endpoint of Identity Server. Any tips by any chance on how to proceed?
You need to use [AllowAnonymous] attribute on your POST action for single sign out in your client application. The user in this case is validated not by cookie, but by the logout_token that Identity Server passes in the POST call.
I want to test an API which has the followoing instruction:
This API requires the caller to have an authenticated user web session.
When I login to the application and send a GET request in other tab it works. But I want to send a PUT request now so I cannot use browser. How can I have an authenticated user session while sending request through some other rest client. For eg: postman/ mozilla rest client.
I have tried logging into application through chrome and then using postman rest client. But it did not work. I have also tried Basic authentication providing application username and password.
So, given you mentioned you're using JWT, your API is most likely handing out this token upon logging in. At this moment your web client (javascript?) is probably storing it somewhere (cookie, local storage, session storage… – you can use your browser's dev tools to inspect). For all subsequent requests, this token is attached. If this token is getting persisted as a cookie, the browser itself takes care of attaching it to every request. If it is persisted somewhere else, your client has to "manually" attach this token to every request.
If you want to test your API call, first you need to login and get your hands on the token. Then, for all authenticated requests, you need to attach this token (probably as the Authorization HTTP header).
I am a beginner to django rest framework (and to REST in general) and I have a server side which (for now) has a UserViewSet which allows to register new users and I can POST to the url from my android app just fine (I get 201 CREATED).
I read a lot about it, but I don't seem to fully the understand the concept of Login and Authentication in REST frameworks and specifically in django rest framework, and how it works.
Do you "Log in" (like in facebook for example) and then you can make requests?
What I understand\heard off:
you can Login to a API\website using your username and password (assuming off course that you have registered as a user and you are in the user database).
After you are Logged in - you will be able to make requests to views that allow access only to logged in\authenticated users.
Is that somewhat correct? I mean, is there a "Log in" url where you login and that's it? you are authenticated?
Also read somewhere that there isn't actually a login url, and you have to add your username and password to each request and then the request has to check if your details are in the User database?
To sum up, I am not really sure how does authentication/logging in (same thing?) happens in django REST framework... and would really appreciate a good explanation or an example..
Thanks a lot!
In a normal web application (removing the API from the question), a user would "log" in with their credentials (username/password, social tokens, etc.) and would receive a session cookie (assigned by Django) that allows them to authenticate in future requests on behalf of a user (realistically, themselves). This session cookie stays on their system for a limited period of time (two weeks by default) and allows them to freely use the website without authenticating again. If the session cookie needs to be removed, such that the person can no longer authenticate, the web application typically destroys the session cookie (or clears the session) which effectives "logs them out".
In the case of an API, it all depends on how the authentication works.
SessionAuthentication works just like as described above, as it uses Django's internal session system.
TokenAuthentication remembers the authentication information through a database-backed token (which is transmitted in the Authorization header) instead of a session cookie.
BasicAuthentication authenticates on every session (no persistent session) by passing the username and password on every request (base64 encoded through the Authorization header).
Other authentication methods generally work in the same way as TokenAuthentication.
So, here are some answers to specific questions which were raised
Do you "Log in" (like in facebook for example) and then you can make requests?
Using BasicAuthentication, you "log in" on every request by providing your credentials. With token-based authentication (TokenAuthentication, OAuth 2, JWT, etc.), you "log in" to receive the initial token and then your authorization is confirmed on every request.
Also read somewhere that there isn't actually a login url, and you have to add your username and password to each request and then the request has to check if your details are in the User database?
This is basic access authentication which you can use in DRF using the BasicAuthentication class.