Skipping keycloak's session cookie - oauth-2.0

I'm using keycloak 4.3.8.final.
I want to utilize keycloak's OIDC flow with my own IDP. I don't want to use any session related capabilities from keycloak, only the authorize adn token endpoints.
All good, when user hits keycloak's authorize endpoint, get redirected to IDP, login, then get redirected back and then get token from Keycloak.
But when another user performs the same authorize/token scenario on the same browser, right away after the first one, with passed parameter prompt=login, keycloak instead of returning another token, throws the following error:
You are already authenticated as different user <placeholder> in this session. Please logout first.
Seems that even when passed prompt=login, keycloak still checks for valid session. Does anyone had the same problem as me? Does anyone has solution for the problem?
Thanks

Related

OAuth2 code flow refresh token failure with keycloak

I have a scenario where the refresh token fetch periodically fails. Keycloak is the oidc provider, using code flow from a web app. When the access token has expired, the back-end application reaches out to the keycloak token endpoint for a new one using the refresh token - generally, this works. Intermittently, however, the refresh token fails, with "invalid_grant, Token is not active". From everything I've found on SO and elsewhere this is due to clock drift. It's certainly possible, this is all running in containers on VMs on systems I do not control, and I would like to mitigate for the situation.
The system in place actually fails pretty gracefully - just not with an XHR. So if I navigate between logical pages in my single page application, and this scenario occurs, the user does not see anything amiss. When a background fetch happens the user sees an error, but the next request succeeds - here's the sequence of requests that causes it:
/<original-request-endpoint> 302, invalid token, redirect to keycloak auth endpoint for the realm for the user to sign in. The redirect is my logic: if the user is not authenticated, send them to the login page.
/keycloak/...realm/.../auth 302 - the user's session is actually still valid, redirect to my authorization endpoint on the back end with a code.
/authorize 302 - this gets a new access token from the keycloak token endpoint and sets the cookie, so future requests succeed with the new token. Redirect to the landing page.
/landing this is effectively ignored.
I was thinking of trying to duplicate the keycloak auth request on the back end if the token refresh fails - but I don't like that idea, it feels messy, I'll need to reconstruct all the request context (cookies etc.) for this special scenario.
Any idea what I'm doing wrong or a better approach to handling refresh token failure?

ORY Hydra and validating an OpenID Connect login

Does ORY Hydra currently have a feature that verifies if a client is logged in via OpenID Connect? I notice there is an API to logout via front-channel
When a user revisits the identity provider, however, I have no way of knowing if they are currently logged in or not. They could delete their client-side HTTP cookies and then I am out of sync with Hydra. Meaning: Hydra has them as logged in, but I have them now as logged out. Also, in the event of a back-channel logout, I want to be able to query for this state.
Is there an API I am overlooking that allows me to know whether a client currently has an active OpenID Connect login via Hydra?
It appears as of right now the only thing one can do is redirect the user to the authorization endpoint since we have no way of knowing if they are authorized or not.
The following two tables that ship with Hydra seem to be the source of truth for the data I am after: hydra_oauth2_access and hydra_oauth2_authentication_session. Does it ever make sense to query those directly if there is no supported HTTP API out of the box to see if a user has an active authentication session?
Sending an authentication request via a redirect to the Provider including prompt=none addresses this use case: it will silently login and return new tokens if there's an ongoing SSO session at the Provider, it will return an error code login_required if not.
Notice there will never be explicit user interaction in both cases so this is convenient (and meant) to run in an hidden iframe.
LOGGED IN STATE
An OAuth client is most commonly a UI application with multiple users. Each user's logged in state is represented by an Authorization Server session cookie that neither the application or user have access to:
The Authorization Server (AS) issues an SSO cookie, to be stored in the system browser for the AS domain
Both Web UIs and Native UIs send it implicitly on subsequent requests, when they invoke the system browser
AUTHORIZATION REDIRECTS
When an OAuth UI redirects the user, it is generally unknown whether:
The user will be prompted to login
The user will be signed in silently (eg the user could have signed in to another app)
For a Web UI it is possible to send an authorization redirect on a hidden iframe with a prompt=none parameter. If the user needs to sign in a login_required error code will be returned. See my Silent Token Renewal Page for further details.
This is not fully reliable however, and has some browser issues in 2020. Also it may be unsuitable if you are using a different type of client.
FEDERATED LOGINS
In some setups the AS redirects further to an Identity Provider (IDP), and the user's login state is further influenced by an IDP session cookie.
There is no way for an app to get hold of the user's IDP login state, since the app only ever interacts with the AS.
IS THERE A USABILITY PROBLEM?
If so, post back and we can discuss further ...

How to give user JWT token after OAuth provider redirect?

I'm implementing OAuth (using rauth) and will be giving JWT tokens (using flask-jwt), javascript frontend (Angular1). I have done it for classical cookie/session based app. It works. Now I want to do it with JWT tokens.
If I understand correctly, user is redirected to provider (ex. Google), login into account, my server and provider do the magic, then provider redirect user back to my page. Now I got user profile and that ends the OAuth part. With normal session you give user cookies and the rest of stuff for setting up session, then redirect him to home page.
This is where I'm stuck. Is there any good practice how to give user JWT token after provider send him back? Give it to user as cookie on redirect to home page? Put it in header? As far as I know I need javascript to save token into LocalStorage/SessionStorage.
At the end of the day, the user will be redirected back to our app where a page now needs to be rendered. The only option I see is to return the JWT as a cookie because response headers aren't accessible in Javascript & the only other place would be to embed it in the DOM which would open it up to CSRF attacks.
When the browser is redirected from the OAuth provider it will only have an access code which can be exchanged for an access token on the server side. But best practice says you need to keep that access token secret (not pass it back to the browser).
There is a lot of debate about JWT's in cookies vs local/session storage but in this use-case I don't see any other option than to use cookies. All the use-cases I have seen that describe using browser storage assume an XHR request is being made to obtain the JWT. But this isn't an option in an OAuth flow because the entire browser has just been redirected back to our app.
I don't see another option (for the OAuth use-case) other than keeping the JWT in a cookie to be used for future API calls. But maybe I'm missing something.
Before passing control to Facebook auth, you can initiate a socket connection to your API, then probably show a loading status in your app. Afterwards let Facebook do it's thing. When it succeeds, it posts data to your backend. Your backend does it stuff and passes the JWT to frontend using the socket it created earlier. This seem like too much work & could come with extra bugs if you don't do it correctly.
const jwt = require("jsonwebtoken");
module.exports = {
signToken: function (payload) {
return jwt.sign(payload, "secret");
},
};

Prompt for AD credentials on every OAuth2 authorize request

We have an application with its own authentication, for which we recently added OAuth2 support. A corporate customer can specify the data for his ADFS or Google domain, and we use that to automatically sign up and log in their users.
Now, the problem is switching credentials. When we log out from our application, clicking the login button (which redirects to the configured ADFS OAuth2 authorize endpoint) will immediately validate the user and send him back to our app, with a valid code for his current credentials.
The Google endpoint has a special parameter, approval_prompt, which we can use to force an intermediate step, at which the user can switch his credentials. I don't think ADFS has that.
What other solutions do we have? Is it possible to configure something on the ADFS server that would prompt the user to enter his credentials for every authorize request?
Here's how those url parameters work, as best as I understand them:
wa is the operation we're requesting. So far, I've only seen two values: wsignin1.0 and wsignout1.0
wfresh has something to do with the max age of cached credentials, but I don't entirely understand it. 0 means don't use cached credentials.
wtrealm is the AppID configured in ADFS. This tells the ADFS server which app is trying to authenticate. For us, this is the base url of the app.
wctx is some app-specific data returned to the app from the ADFS server after the request. Since we're using the standard System.IdentityModel setup, it handles parsing and reacting to this value, not our code. There's an ru parameter encoded inside it. This is the return url. This is how we get back to the page we came from.
wct is the timestamp of the authentication request
For us adding the parameter prompt=login to que authorization request URL is working with OAuth2 :
/adfs/oauth2/authorize?response_type=code&client_id=XXX&resource=YYY&redirect_uri=ZZZZ&prompt=login

Web API [Authorize] Attribute Without User Logging In Or Requesting Token With Password?

Correct me if I'm not understanding something. I'm working with a fresh Web API application generated from a VS template.
The user does register right on the login page of the Web API app.
It appears that a user can register from outside the Web API app (from ANY device that knows the api/Accounts URL), but it requires passing sensitive information in plain text.
The sample ValuesController has the [Authorize].
Accessing /api/Values from the browser will throw a 401 if the user is not logged in.
Accessing /api/Values from Fiddler will also throw a 401 even if the user is logged in. This is because it requires an Authorize: Bearer header, which the access token isn't available from outside the web application.
There is a token endpoint that we can use to request a token from outside the app, but using the built-in token endpoint requires the user's username and password as plain text to be sent.
I guess all the work needs to be done from an external trusted client application (which must have access to the same database that stores user info). From the client application, how would I create an access token so that I can make a request that would have that access token in the header?
Suppose that I was able to achieve generating an acceptable access token from the client. Will the [Authorize] attribute still block access because the user would technically not be logged in? Or does [Authorize] actually log the user in if it doesn't result in a 401?
The AuthorizeAttribute will block access when the IsAuthenticated property of the current IIdentity is false. This is entirely separated from the access token.
Your steps are all right. But i think you are mixing you understanding of the last part with cookies authentication and token authentication.
Will the [Authorize] attribute still block access because the user
would technically not be logged in? Or does [Authorize] actually log
the user in if it doesn't result in a 401?
With cookie authentication this would be a problem that the user would technically need to be logged in and a valid session would need to exist on the server.
However this would not be the case on with token authentication. As long as you have a valid bearer token, you may access the api from any device.

Resources