Hello guys i am working on a web application and im in the part of authenticating my user.
Im sorry if there is already an awsner but i couldn't find it...
I have this sample code that works but gives me a popup (what i want is redirect):
var googleUser = {};
gapi.load('auth2', function () {
// Retrieve the singleton for the GoogleAuth library and set up the client.
auth2 = gapi.auth2.init({
client_id: 'my_client_id',
cookiepolicy: 'single_host_origin',
//ux_mode: 'redirect' //tried with redirect but i don't get user on object on click handler
});
auth2.attachClickHandler(document.getElementById('loginG'), {},
function (googleUser) {
var usermail = googleUser.getBasicProfile().getEmail();
var username = googleUser.getBasicProfile().getName();
var userimage = googleUser.getBasicProfile().getImageUrl();
console.log(googleUser);
});
});
So with this code i can get the user information/token and login into the app, but this happens with a popup and i want to do it with redirect like it's done on this website: https://www.realfevr.com/en/home-page/
I tried doing it with ux_mode: redirect and it does in-fact redirect the login but I can't get the object of the user so i must be doing something wrong here...
Can someone explain me what I am doing wrong to not get the user from the redirect ?
Related
I followed this - http://docs.identityserver.io/en/release/quickstarts/7_javascript_client.html.
Using the following configuration, I tried to login Identity Server from my ReactJS app. http://localhost:3000/callback.html is loaded after successful login. I got id_token and access_token in the url. But, I am sure this callback.html is not the 'src\callback.html' which I have in the folder structure. Even if I delete the 'src\callback.html' file, http://localhost:3000/callback.html#id_token=....... is still loaded. May I know how to change the redirect_uri to a view in my React app (for example Home.js rather than an html file)? I hope I should use route for this. Please advise.
var config = {
authority: "http://localhost:5000",
client_id: "reactSpa",
redirect_uri: "http://localhost:3000/callback.html", // I want it to be something like 'http://localhost:3000/components/home' (a view not an html)
response_type: "id_token token",
scope: "openid profile api1",
post_logout_redirect_uri: "http://localhost:3000/index.html", // same here
};
PS:
I need to set the redirect_uri and post_logout_redirect_uri to any of the views in my React app (not html files) so that I can do the following operation in my Callback view.
new Oidc.UserManager().signinRedirectCallback().then(function () {
window.location = "index.html"; // should be just 'index'
}).catch(function (e) {
console.error(e);
});
First, you need to change client's RedirectUris on identityserver side. I don't know which storage you use but if you use in memory clients here is a sample from official docs:
var jsClient = new Client
{
ClientId = "js",
ClientName = "JavaScript Client",
ClientUri = "http://identityserver.io",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { "http://localhost:7017/index.html" },
PostLogoutRedirectUris = { "http://localhost:7017/index.html" },
AllowedCorsOrigins = { "http://localhost:7017" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"api1", "api2.read_only"
}
};
And also you need to change redirect_uri appropriately on client side config(it must be same as identityserver).
The following comment is the answer:
//Did you try to change redirect_uri on identityserver config to http://localhost:7017/callback and create a Callback component with route configuration(like )? – adem caglin//
It worked after I added Route.
We plan to use keycloak to secure a bunch of web apps, some written in Java, some in JavaScript (with React).
After the user is logged in by keycloak, each of those web apps needs to retrieve the user that is logged in and the realm/client roles that the user has.
For Java apps, we tried the keycloak Java API (request -> KeycloakSecurityContext -> getIdToken -> getPreferredUsername/getOtherClaims). They seem to work fine
For JavaScript apps, we tried the following code, but could not get Keycloak to init successfully (Note this is in web app code after the user is already authenticated by keycloak, the app is only trying to retrieve who logged in with what roles):
var kc = Keycloak({
url: 'https://135.112.123.194:8666/auth',
realm: 'oneRealm',
clientId: 'main'
});
//this does not work as it can't find the keycloak.json file under WEB-INF
//var kc = Keycloak('./keycloak.json');
kc.init().success(function () {
console.log("kc.idToken.preferred_username: " + kc.idToken.preferred_username);
alert(JSON.stringify(kc.tokenParsed));
var authenticatedUser = kc.idTokenParsed.name;
console.log(authenticatedUser);
}).error(function () {
window.location.reload();
});
I assume it would be fairly common that web apps need to retrieve current user info. Anyone knows why the above code didn't work?
Thanks.
<script src="http://localhost:8080/auth/js/keycloak.js" type="text/javascript"></script>
<script type="text/javascript">
const keycloak = Keycloak({
"realm": "yourRealm",
"auth-server-url": "http://localhost:8080/auth",
"ssl-required": "external",
"resource": "yourRealm/keep it default",
"public-client": true,
"confidential-port": 0,
"url": 'http://localhost:8080/auth',
"clientId": 'yourClientId',
"enable-cors": true
});
const loadData = () => {
console.log(keycloak.subject);
if (keycloak.idToken) {
document.location.href = "?user="+keycloak.idTokenParsed.preferred_username;
console.log('IDToken');
console.log(keycloak.idTokenParsed.preferred_username);
console.log(keycloak.idTokenParsed.email);
console.log(keycloak.idTokenParsed.name);
console.log(keycloak.idTokenParsed.given_name);
console.log(keycloak.idTokenParsed.family_name);
} else {
keycloak.loadUserProfile(function() {
console.log('Account Service');
console.log(keycloak.profile.username);
console.log(keycloak.profile.email);
console.log(keycloak.profile.firstName + ' ' + keycloak.profile.lastName);
console.log(keycloak.profile.firstName);
console.log(keycloak.profile.lastName);
}, function() {
console.log('Failed to retrieve user details. Please enable claims or account role');
});
}
};
const loadFailure = () => {
console.log('Failed to load data. Check console log');
};
const reloadData = () => {
keycloak.updateToken(10)
.success(loadData)
.error(() => {
console.log('Failed to load data. User is logged out.');
});
}
keycloak.init({ onLoad: 'login-required' }).success(reloadData);
</script>
simple javascript client authentication no frameworks.
for people who are still looking...
Your code asks the Keycloak client library to initialize, but it doesn't perform a login of the user or a check if the user is already logged in.
Please see the manual for details: http://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter
What your probably want to do:
Add check-sso to the init to check if the user is logged in and to retrieve the credentials keycloak.init({ onLoad: 'check-sso' ... }). You might even use login-required.
Make sure that you register a separate client for the front-end. While the Java backend client is of type confidential (or bearer only), the JavaScript client is of type public.
You find a very minimal example here: https://github.com/ahus1/keycloak-dropwizard-integration/blob/master/keycloak-dropwizard-bearer/src/main/resources/assets/ajax/app.js
Alternatively you can register a callback for onAuthSuccess to be notified once the user information has been retrieved.
Once you use Keycloak in the front-end, you will soon want to look in bearer tokens when calling REST resources in the backend.
You might have solved the problem by this time. I hope this answer help rest of the people in trouble.
when you use JavaScript Adopter
Below javascript should be added in of html page.
<script src="http://localhost:8080/auth/js/keycloak.js"></script>
<script>
/* If the keycloak.json file is in a different location you can specify it:
Try adding file to application first, if you fail try the another method mentioned below. Both works perfectly.
var keycloak = Keycloak('http://localhost:8080/myapp/keycloak.json'); */
/* Else you can declare constructor manually */
var keycloak = Keycloak({
url: 'http://localhost:8080/auth',
realm: 'Internal_Projects',
clientId: 'payments'
});
keycloak.init({ onLoad: 'login-required' }).then(function(authenticated) {
alert(authenticated ? 'authenticated' : 'not authenticated');
}).catch(function() {
alert('failed to initialize');
});
function logout() {
//
keycloak.logout('http://auth-server/auth/realms/Internal_Projects/protocol/openid-connect/logout?redirect_uri=encodedRedirectUri')
//alert("Logged Out");
}
</script>
https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter Reference Link.
Note : Read the comments for 2 methods of adding json credentials.
Context
I'm attempting to create an Android app with Nativecript using JavaScript. On the first page, it asks the user to connect with Facebook, and I intend to verify whether or not an account exists with their email address.
Tools
I'm using the nativescript-oauth package to handle the OAuth connection to Facebook. I'm working on a Windows 10 machine via command line.
Code
app.js
var tnsOAuthModule = require("nativescript-oauth");
var facebookInitOptions = TnsOAuthOptionsFacebook = {
clientId: 'REDACTED',
clientSecret: 'REDACTED',
scope: ['email']
};
tnsOAuthModule.initFacebook(facebookInitOptions);
application.start({ moduleName: "views/start/start" });
start.js
//...
var tnsOAuthModule = require("nativescript-oauth");
//...
exports.fbConnect = function(){
console.log("Facebook Connect button tapped");
tnsOAuthModule.login()
.then(()=>{
console.log('logged in');
var token = tnsOAuthModule.accessToken();
console.log("FB Auth token: " + token);
console.log(JSON.stringify(tnsOAuthModule));
})
.catch((er)=>{
console.log(er);
});
console.log("Login sucessful");
}
What goes wrong
The above outputs the following:
JS: Facebook Connect button tapped
...
JS: logged in
JS: FB Auth token: EAAC50oamJosBAF1F3lrGAOntENgSAZA40w4iE3rNOLP1W_REDACTED_Cb7yS9ZB1Ro4qhLroOMwZD
JS: {"instance":{"tokenResult":{"accessToken":"EAAC50oamJosBAF1F3lrGAOntENgSAZA40w4iE3rNOLP1W_REDACTED_Cb7yS9ZB1Ro4qhLroOMwZD","accessTokenExpiration":"2017-03-24T18:27:04.176Z","refreshTokenExpiration":"2017-03-24T18:27:04.176Z"},"credentials":{"authority":"https://www.facebook.com/dialog","tokenEndpointBase":"https://graph.facebook.com","authorizeEndpoint":"/oauth","tokenEndpoint":"/v2.3/oauth/access_token","clientId":"REDACTED","clientSecret":"REDACTED","redirectUri":"https://www.facebook.com/connect/login_success.html","scope":"email"}}}
JS: Application started successfully
As you can see, I successfully authorise the Facebook app and retrieve a working access key and can parse the object that is returned - however I'm trying to retrieve the users' email address. I can see that the "email" is within the scope.
Question
How can I use the nativescript-oauth plugin, or the data from the above object, to retrieve the users' email address, as defined the in scope?
Resources
Nativescript homepage - https://www.nativescript.org/
nativescript-oauth GitHub page - https://github.com/alexziskind1/nativescript-oauth
Nativescript official release of OAuth plugin - https://www.nativescript.org/blog/introducing-the-nativescript-oauth-plugin
You must change the scope to get more details(add "user_friends" to get their friend's list, add "public_profile" for profile info)
var facebookInitOptions = TnsOAuthOptionsFacebook = {
clientId: 'REDACTED',
clientSecret: 'REDACTED',
scope: ['email', 'user_friends', 'public_profile']
};
Lastly, in your "App review" section of your facebook developer page, ensure those scope fields are active and shown(they will have a green dot next to them with description of data). You might need to make the app live/start a submission to get approval first if the above code doesn't work.
I currently have an issue with one of my apps.
The issue is that a user can keep the page open for a prolonged period of time before entering any data, so occasionally, when they enter data and hit the submit button, they are redirected to o365 for authentication and therefore lose the entered data.
I have all the standard authentication working for the app. However, i believe in order to do this, i would need to get a refreshed token in javascript when the submit button is clicked, and send this token to an api method in order to give access.
Is this possible and does anybody know how to go about it?
It is an MVC ASP.NET application using Owin O365 security with Microsoft Azure AD.
I am not sure what information or code snippets would be relevant here so if there is anything i can provide, please ask.
I have found multiple examples of getting tokens etc with angular, however, this is not an SPA and does not use angular.
Many Thanks in advance.
UPDATE
I have attempted to retrieve a token using ADAL JS using the following code but it doesnt seem to recognise the AuthorizationContext(config) call:
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/adal.min.js"></script>
$('#btnSubmit').on('click', function (e) {
e.preventDefault();
CheckUserAuthorised();
});
function CheckUserAuthorised() {
window.config = {
instance: 'https://login.microsoftonline.com/',
tenant: '##################',
clientId: '###################',
postLogoutRedirectUri: window.location.origin,
cacheLocation: 'localStorage'
};
var authContext = new AuthorizationContext(config); //THIS LINE FAILS
var user = authContext.getCachedUser();
if (!user) {
alert("User Not Authorised");
authContext.login();
}
else {
alert('User Authorized');
}
}
This gives the following error in console:
'AuthorizationContext' is undefined
UPDATE
I have no got passed the undefined error. This was because i was calling AuthorizationContext rather than AuthenticationContext. Schoolboy error. However now, whenever i check the user property of the context, it is always null. And i do not know a way around this as the context is initialised on page load.
There is a lack of a step in your code, here is a simple code sample, hope it will help you:
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.10/js/adal.min.js"></script>
<body>
login
access token
get user
</body>
<script type="text/javascript">
var configOptions = {
tenant: "<tenant_id>", // Optional by default, it sends common
clientId: "<client_id>",
postLogoutRedirectUri: window.location.origin,
}
window.authContext = new AuthenticationContext(configOptions);
var isCallback = authContext.isCallback(window.location.hash);
authContext.handleWindowCallback();
function getToken(){
authContext.acquireToken("https://graph.microsoft.com",function(error, token){
console.log(error);
console.log(token);
})
}
function login(){
authContext.login();
}
function getUser(){
var user = authContext.getCachedUser();
console.log(user);
}
</script>
The code sample is from the answer of No 'Access-Control-Allow-Origin' header with Microsoft Online Auth. The issues are different but they are in the same scenario.
any further concern, please feel free to let me know.
I found a similar example on the web and your problem seems to be related to the object you are instantiating.
Instead of
new AuthorizationContext(window.config);
try
new AuthenticationContext(window.config);
The code ran just fine showing that the user was not authenticated.
I am using following code for users to be able to login using their Google account via Javascript API.
HTML
<a id="gp_login" href="javascript:void(0)" onclick="javascript:googleAuth()">Login using Google</a>
Javascript
function gPOnLoad(){
// G+ api loaded
document.getElementById('gp_login').style.display = 'block';
}
function googleAuth() {
gapi.auth.signIn({
callback: gPSignInCallback,
clientid: googleKey,
cookiepolicy: "single_host_origin",
requestvisibleactions: "http://schema.org/AddAction",
scope: "https://www.googleapis.com/auth/plus.login email"
})
}
function gPSignInCallback(e) {
if (e["status"]["signed_in"]) {
gapi.client.load("plus", "v1", function() {
if (e["access_token"]) {
getProfile()
} else if (e["error"]) {
console.log("There was an error: " + e["error"])
}
})
} else {
console.log("Sign-in state: " + e["error"])
}
}
function getProfile() {
var e = gapi.client.plus.people.get({
userId: "me"
});
e.execute(function(e) {
if (e.error) {
console.log(e.message);
return
} else if (e.id) {
// save profile data
}
})
}(function() {
var e = document.createElement("script");
e.type = "text/javascript";
e.async = true;
e.src = "https://apis.google.com/js/client:platform.js?onload=gPOnLoad";
var t = document.getElementsByTagName("script")[0];
t.parentNode.insertBefore(e, t)
})()
This code is working fine.
I want to use the above code (using Javascript) to login user from their Google account without triggering a popup window. Like, user clicks the login link, asked for app permissions in the same window/tab, user grants permission, user redirected back to the page where Google login link was, profile data is saved and user is logged in.
You can the use ux_mode parameter (options are 'redirect' or 'popup') and set a redirect_uri if you want to redirect to a different page.
It's also necessary to authorize the URL for the OAuth client on your google project page.
function initClient() {
gapi.client.init({
apiKey: API_KEY,
clientId: CLIENT_ID,
discoveryDocs: DISCOVERY_DOCS,
scope: SCOPES,
ux_mode: 'redirect',
//redirect_uri: custom url to redirect'
}).then(function () {
// Listen for sign-in state changes.
gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
// Handle the initial sign-in state.
updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
authorizeButton.onclick = handleAuthClick;
signoutButton.onclick = handleSignoutClick;
});
}
Such functionality is not provided through Google API. You should stick with gapi.auth.signIn. I know just one way to make it work, but it's very hacky.
gapi.auth.signIn opens authentication window.
Save authentication window url in your app1.
Instead of calling gapi.auth.signIn, redirect user to that url.
To redirect successful authentication back to your website, add/modify redirect_url param in the url2. Keep in mind that redirect_uri must be registered in developers console.
Example:
https://accounts.google.com/o/oauth2/auth?client_id=1234567890.apps.googleusercontent.com&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fplus.login&immediate=false&response_type=token&redirect_uri=http://example.com
This way google will redirect user back to your website. access_token is provided through GET params.
1If google changes their API this may break (since this method bypasses JS API and assumes that all those params in the url will be supported for ever).
2Redirect_url is introduced in offline access flow documentation. I don't think this param was intended to work in any other cases.
I strongly advise not to use this idea (since it bypasses JS API and uses undocumented functionality). Stick with gapi.auth.signIn.