Skip to content

Inline authentication#16910

Open
damencho wants to merge 6 commits intomasterfrom
authentication-update
Open

Inline authentication#16910
damencho wants to merge 6 commits intomasterfrom
authentication-update

Conversation

@damencho
Copy link
Member

@damencho damencho commented Feb 6, 2026

No description provided.

@damencho damencho force-pushed the authentication-update branch from 7535a5b to d856378 Compare February 6, 2026 22:27
squash: Adds refresh token use when refresh token is needed on connection resuming.
squash: Fix bugs and move to PKCE flow.
@damencho damencho force-pushed the authentication-update branch from d856378 to 7a93da7 Compare February 7, 2026 15:21
const config = state['features/base/config'];

// if we have auto redirect enabled, and we have previously logged in successfully
// let's redirect to the auth url to get the token and login again
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need this anymore? Why?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well this was setting the jwt on prejoin without clicking join. But this means it is invoked without user interaction and that does not work with popups, the browser blocks them. So I moved this to happen before we join, after clicking the join button.


const nonce = generateNonce();

sessionStorage.setItem('oauth_nonce', nonce);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this? where do we use it? I see that we remove it but I don't see where we get it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is sessionStorage.setItem( so we set it here. We generate it.
Hum, I think it was used for verifying the response in sso.html. Probably we do not do it at the moment, but we can add it. I will double check when I do the changes for the other PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is now implemented.

window.addEventListener('message', handler);

// Check if popup was closed
const checkClosed = setInterval(() => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems kind of dirty. Maybe we can do a message that will let us know that the popup will close so that we can cleanup or something else?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do close it on error or success few lines above, this is the backup plan.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure but still. Don't we have another option of handling this?

Also currently if we close the popup from the handler this interval will still run and execute and will call reject....

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I dropped the auto closing logic ... if something goes wrong we need to see it and have the popup open otherwise there is no trace what happened.

@damencho damencho force-pushed the authentication-update branch from 6179ba6 to 1cc639a Compare February 11, 2026 15:01

const nonce = generateNonce();

sessionStorage.setItem('oauth_nonce', nonce);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should check if the session storage is enabled. If it is disabled trough the browser settings this will throw an exception.

};

// Listen for messages from the popup
window.addEventListener('message', handler);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should add the listener to popup. this way if the user closes the popup the listener will be auto removed! otherwise in this use case we will be leaking listeners.

const state = {
tenant: string | undefined,
refreshToken?: string | undefined): object => {
const state: any = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why the any? If we need to specify a type lets define a real one and use it. It might be useful to have a type for this state anyway...

tenant: string | undefined): Promise<string | undefined> => {
tenant: string | undefined,
// eslint-disable-next-line max-params
refreshToken?: string | undefined): Promise<string | undefined> => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering since we have ? do we need the undefined type?

const refreshToken = state['features/base/jwt'].refreshToken;

if (typeof APP !== 'undefined' && jwt
&& validateJwt(jwt).find((e: any) => e.key === JWT_VALIDATION_ERRORS.TOKEN_EXPIRED)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to do this since from the error we know the jwt is expired?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I will drop it.

.then((url: string | undefined) => {
if (url) {
// only if it is inline token auth and token is about to expire
// if not expired yet use it to refresh the token
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused from this comment. Isn't the token expired for sure in this case?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah the other check was checking 30 seconds earlier ... but in the ljm I did it exact check. Will fix the comment.

if (url) {
// only if it is inline token auth and token is about to expire
// if not expired yet use it to refresh the token
dispatch(showNotification({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering about the use case where the jwt is passed externally from the URL.

It seems to me that even in this case the user will be prompted to login again which would be wrong I guess because the embedder of the meeting would expect to work only with their jwt token. Is this correct or I'm missing something? If this is the case maybe we should show different error message in this case and have a config that would disable the whole login thingy. WDYT?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you are right. I will check it as jaas case is different than this ...

store.dispatch(setDelayedLoadOfAvatarUrl());
store.dispatch(setKnownAvatarUrl(delayedLoadOfAvatarUrl));
}
break;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting. was this an old bug?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but it was not cause any problem because of the first if in setJwt functinon.

store.dispatch(hideNotification(PROMPT_LOGIN_NOTIFICATION_ID));

if (isTokenAuthInline(state['features/base/config'])) {
// Use refresh token if available, otherwise fall back to silent login
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate on the comment? I don't understand it.

It seems to me that we always open a popup. What is the silent login?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will take a look and fix it. I experimented with several options, there is this silent login that is supported from keycloak but modern browsers stop it most of the times, due to security concerns.


dispatch(authStatusChanged(true, email || ''));
// it may happen to be already set (silent login)
dispatch(authStatusChanged(true, email || getState()['features/base/conference'].authLogin || ''));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm kind of lost what is the silent login?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the comment above, I will go through the comments and fix them all.

});
}

store.dispatch(authStatusChanged(true, jwtPayload.email));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we started setting the email?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we can show it in settings -> profile which is the indication that you are logged in.
If email is missing from the state of authentication feature (if I remember correctly) it means you are not logged in.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm I thought it is the first argument which we set to true here, isn't it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope ... it has some other semantics ... and some comment that we will remove it ...

Copy link
Member

@hristoterezov hristoterezov Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually you are correct! but why did we started dispatching this one here?

I see that we also do the same on connection established. do we need both?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have the email from jwt on connection established ... if we are going from anonymous (no token) to setting a token we need it here I think.

@damencho
Copy link
Member Author

Screenshot 2026-02-11 at 8 34 25 AM

joinConference();
// if we have auto redirect enabled, and we have previously logged in successfully
// let's redirect to the auth url to get the token and login again
if (tokenPreAuthConfig) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually why did we moved this to be executed on join and not when the user loads the page?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, cause when you join the page there is no user interaction, while clicking join button is user interaction. Otherwise popups do not work and are blocked by the browser.

<script>
// Notify parent window that logout is complete
if (window.parent) {
window.parent.postMessage({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we use this file?

<div id="error" class="error"></div>
</div>

<script>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like pretty large JS. Does it make sense to put it in a separate file? Maybe even a new bundle to be sure about browser compatibility and maybe we will be able to reuse some code? WDYT?

window.opener.postMessage(message, window.location.origin);

// Auto-close after a short delay
setTimeout(() => window.close(), 1000);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't the opener already closing the popup?

}

// Get authorization code
const code = urlParams.get('code');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this coming from?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants