Okta Widget NOT Rendering - javascript

Currently, using 1.6.0 of the scripts and CSS files. I have the widget integrated in my Angular 1.5.x app. I have been experiencing issues receiving 404 when trying to render the OKTA Widget as its GET request to:
https://*.oktapreview.com/api/v1/sessions/me
Which means that the widget gets rendered once and I am able to log in, but once I log out, I am not able to re-render the widget without having to refresh the browser first.
Has anyone found and resolved this issue?

I think this might be related to this Stack Overflow issue. Can you check your privacy settings?
The reason for this issue is because the widget exchanges the sessionToken (which you get after logging in) with an id_token via a hidden iframe, at which time the session cookie is also set. But, since this is in an <iframe>, it's considered a third-party cookie.
There is currently no good way around this when your browser has third-party cookies disabled without redirecting to Okta to set the session cookie. A new version (1.8.0) of the widget is going to be released this week will make this easier (See this commmit which addresses this issue). With this new version, passing in authParams.display = 'page' will perform the call to /authorize via a redirect rather than through the hidden iframe.

Now that 1.8.0 is available via Okta's CDN, here is a sample of how to use the authParams.display = 'page' setting described above:
<script>
var config = {
baseUrl: 'https://YOUR-OKTA-ORG-HERE.okta.com',
clientId: 'YOUR-OKTA-CLIENT-ID-HERE',
redirectUri: 'YOUR-REDIRECT-URL-HERE',
authParams: {
responseType: 'code',
display: 'page',
scopes: ['openid', 'email', 'profile'],
}
};
var oktaSignIn = new OktaSignIn(config);
oktaSignIn.renderEl({ el: '#app-container' }, () => {});
</script>

Related

Google OAuth code flow, can't exchange code for token with error "redirect_uri_mismatch"

I'm implementing social login on my website.
I was able to implement the "One tap" flow, but I need to have an alternative to handle the "cooldown" which prevents the popup from appearing, if the user blocked it or closed it.
So I followed the "Authorization" flow on Google documentation.
Until yesterday morning everything was working fine and I succesfully exchanged the code with a token by calling
https://oauth2.googleapis.com/token
or
https://accounts.google.com/o/oauth2/token
sending secret and everything.
In a first instance I used Postman, then I made a sample code in a Spring project, before preparing the final code in another Spring project.
The first run in the final project I started getting a 400 error, with the redirect_uri_mismatch error key.
And then I was never able to do the exchange anymore, I get the same error from Postman as well.
The config is correct (It never changed from when it was working).
How can I solve this??
Here's some code
FRONTEND
this.client = google.accounts.oauth2.initCodeClient({
client_id: this.clientId,
scope: "openid profile email",
ux_mode: "popup",
redirect_uri: this.redirectUri,
callback: (response) => {
debugger;
this.submitFakeForm({
clientId: this.clientId,
code: response.code
});
}
});
this.client.requestCode();
POSTMAN PARAMS
this.redirectUri is identical to the one passed here and set up on Google credentials
FOR THE MOST SKEPTICAL, THE AUTHORIZED REDIRECTS :)
They're repeated in couples, because one is for local development, one is for the integration environment.
And of course the production config is on another credential.
Nowhere in the docs is this, but I came across this answer here on stackoverflow and it's basically suggesting not to pass the real redirect_uri, but to use a fixed string postmessage.
I want to point up again that I was using the real redirect_uri yesterday and it worked.
I will do some tests again in the future and update here if something changes.
For now just know that using postmessage fixed the issue for me
also I will be using https://oauth2.googleapis.com/token as endpoint, since it's the one mentioned in the (awful) docs, although https://accounts.google.com/o/oauth2/token works just as well.

Google oauth session lost after page reload (javascript)

I recently moved from the deprecated gapi.auth2 to the new Google Identity Services, using the javascript client library, and noticed a big difference: if someone signs in, and then reloads the page, the session is lost, and has to sign in again, every time the page is loaded. This was not the case with the deprecated library.
The problem can be easily reproduced with the Calendar API example.
Is there any configuration option to keep the session persistent? Or do I need to store the access tokens somehow? I could not find anything relevant in the official docs.
UPDATE:
The migration guide states the following:
Previously, Google Sign-In helped you to manage user signed-in status using:
Callback handlers for Monitoring the user's session state.
Listeners for events and changes to signed-in status for a user's Google Account.
You are responsible for managing sign-in state and user sessions to your web app.
However there's absolutely no information on what needs to be done.
UPDATE 2
To be more specific, the actual issue is not making the session persistent. Managing the sign in state and user session is something I can solve.
The real problem is the access token used to call the Google APIs.
As mentioned in the comments, the access tokens are 1) short lived 2) are not stored anywhere, so even if not expired, they do not persist between page reloads.
Google provides the requestAccessToken method for this, however even if I specify prompt: '', it opens the sign-in popup. If I also specify the hint option with the signed in user's email address, than the popup opens, displays a loading animation briefly, and closes without user interaction. I could live with this, however this only works if triggered by a user interaction, otherwise the browser blocks the popup window, meaning that I cannot renew the token without user interaction, e.g. on page load. Any tips to solve this?
I faced all the same issues you described in your question.
In order to help:
Google 3P Authorization JavaScript Library: in this link we can check all the methods the new library has (it does not refresh token, etc..)
This doc says the library won't control the cookies to keep the state anymore.
Solution
Firstly I need to thanks #Sam O'Riil answer.
As Sam described: "you can somehow save access token and use it to speed-up things after page reload."
Given the the Google's exampe, we should call initTokenClient in order to configure the Google Auth and the requestAccessToken to popup the auth:
tokenClient = google.accounts.oauth2.initTokenClient({
client_id: 'YOUR_CLIENT_ID',
scope: 'https://www.googleapis.com/auth/calendar.readonly',
prompt: 'consent',
callback: tokenCallback
});
tokenClient.requestAccessToken({prompt: ''})
In your tokenCallback you can save the credentials you get somehow, e.g.:
const tokenCallback(credentials) => {
// save here the credentials using localStorage or cookies or whatever you want to.
}
Finally, when you restart/reload your application and you initialize the gapi.server again, you only need to get the credentials again and set token to gapi, like:
gapi.load('client', function() {
gapi.client.init({}).then(function() {
let credentials = // get your credentials from where you saved it
credentials = JSON.parse(credentials); // parse it if you got it as string
gapi.client.setToken(credentials);
... continue you app ...
}).catch(function(err) {
// do catch...
});
});
Doing it, your application will work after the reload. I know it could not be the best solution, but seeing what you have and the library offers, I think that's you can do.
p.s.: the token expires after 1 hour and there is no refresh token (using the implicit flow) so, you will have to ask the user to sign-in again.

Unable to use localStorage as cache location in React Native App

I am developing a React Native App with expo-cli. I am using ADFS to authenticate users in the app, and in particular, I am using MSAL.js. I've got the authentication working on web, however, I cannot get the App to run on iOS or Android. I am getting the error: "The cache location provided is not valid. Provided value: localStorage. Possible values are: localStorage, sessionStorage."
I've tried using sessionStorage instead of localStorage, but I just get the same error, except it tells me the provided value was sessionStorage.
I found a thread where someone was having a similar problem as well, here: MSAL UserAgentApplication: Local storage not working. I tried the workaround, but then I get the error: "undefined is not a constructor (evaluating 'new Msal.Storage("localStorage")')".
If I try calling Msal.Storage("localStorage"), it tells me that msal.Storage is not a function.
I've also tried explicitly passing in values to the UserAgentApplication function from my config, rather than passing in the config itself:
var myMSALObj = new Msal.UserAgentApplication(msalConfig.auth.clientId, msalConfig.auth.authority, msalConfig.auth.redirectURI, { cacheLocation: 'localStorage' });
Here's the snippet of code where I believe the problem is:
const msalConfig = {
auth: {
clientId: "<client-Id>",
authority: "<authority>",
redirectURI: "http://localhost:19006"
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: true
}
};
//new Msal.Storage("localStorage");
var myMSALObj = new Msal.UserAgentApplication(msalConfig);
I would expect the call to UserAgentApplication to correctly use the localStorage as cache on both iOS and Android, but this does not seem to be the case. The app works perfectly in my browser on my laptop, though, without any cache/localStorage hiccups. Are there any workarounds/fixes for this that do not require Msal.Storage? Any help is much appreciated!
I just wrote my own library to do it. I guess MSAL.js doesn't have the right calls to work with mobile browsers.
https://yarnpkg.com/en/package/azure-ad-graph-expo
The library below does just what I want, which is log into Azure AD, retrieve a token, and then use that token to query MS graph for the appropriate user data.

How to handle google login for a widget

I'm in the process of creating a widget. The part that escapes me is implementing social media authentication.
The widget is done through embedded javascript, and takes over a <div> on the page rather than utilizing an iframe.
The problem that I am having is that I would like to avoid redirects. Not because I don't want to handle them, but because I want to make the widget as friendly as possible. The basic google signin button creates a popup which handles the authentication client side. It is absolutely perfect for my use case, except that it requires a client_id:
<script>
window.googleStart = function() {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init({
client_id: '639034356632-fgcp4bigtn908q2ev3qifl9vfqnsciuj.apps.googleusercontent.com',
// Scopes to request in addition to 'profile' and 'email'
//scope: 'additional_scope'
});
});
}
</script>
I might be wrong, but I believe that if I use this method while being embedded onto someone's website I could overwrite their client_id and cause conflicts, or perhaps google would just void the second init attempt and use their client_id. In either case I don't believe that's what I should be doing. Is there any way to setup client side authentication without redirection so that my widget does not interfere with the google api that the website may be using?
I have a method that uses redirection and avoids this problem, but I would really like to be able to complete the entire social authentication without moving from the page the widget is embedded on.
You could use a new window target to the gAuth.

Adal.js logging out without a redirect

In our current SPA implementation we authenticate against AzureAD using adal.js and upon successful authentication hit our web api to get the authorization data. There are a couple of edge case scenarios where the get authorization data call could fail. In this case we would like to clear out the state/cache created by adal.js. I have tried a few things but I have not not been able to create a clean slate. Here is some code that I have tried.
localStorage.clear();
var authContext = AuthenticationContext.prototype._singletonInstance;
authContext.clearCache();
authContext._user = null;
I don't want to use the built in logout function. Calling logout redirects the user to the Azure signout page. The UX is pretty wierd so trying to avoid it.
If you want to clear all the cache entries created by adal, clearCache() is the method that should be used, and if you want to clear the cache only for a specific resource entry, then use clearCacheForResource.
But one more thing to note is, these two methods only clear the cache/storage though, it won't clear any session/cookie hold on azure ad, if you want to clear that, then the built in logout should be the one to use.
You could probably try to implement the silent logout(probably using iframe, this will prevent the ux from displaying), and then call clearCache to clear the localstorage/sessionstorage
You can set postLogoutRedirectUri to your aplication setup:
adalProvider.init(
{
instance: 'https://login.microsoftonline.com/',
tenant: 'www.contoso.com',
clientId: '0101001010101',
extraQueryParameter: 'nux=1',
cacheLocation: 'localStorage', // enable this for IE, as sessionStorage does not work for localhost.
endpoints: endpoints,
postLogoutRedirectUri: 'https://www.yourapp.com'
},
$httpProvider
);

Categories

Resources