Loading Keycloak config from URL - javascript

The Keycloak 3.2 Javascript Adapter documentation says you can instantiate the keycloak object with :
var keycloak = Keycloak('http://localhost:8080/myapp/keycloak.json'));
But when I try to do so, it looks like my keycloak.config file is not propertly set as I end up with :
Uncaught TypeError: Cannot read property 'charAt' of undefined
at getRealmUrl (keycloak.js:482)
at Keycloak.kc.createLoginUrl (keycloak.js:233)
at Object.login (keycloak.js:897)
at Keycloak.kc.login (keycloak.js:205)
at doLogin (keycloak.js:121)
at onLoad (keycloak.js:144)
at Object.processInit [as successCallback] (keycloak.js:187)
at Object.setSuccess (keycloak.js:771)
at XMLHttpRequest.req.onreadystatechange (keycloak.js:598)
at XMLHttpRequest.wrapFn [as __zone_symbol___onreadystatechange] (zone.js:1056)
Yet, when I access http://localhost:8080/myapp/keycloak.json with my browser I get :
{
url: 'http://keycloak-server/auth',
realm: 'myrealm',
clientId: 'myapp'
}
and if I instantiate the keycloak object with
var keycloak = Keycloak({
url: 'http://keycloak-server/auth',
realm: 'myrealm',
clientId: 'myapp'
});
everything works fine.
Is this a Keycloak bug, or is there anything I'm missing ?

Keycloak uses a different format whether you load the config from its URL or straight into the constructor...
If you load it via its URL, the format has to be :
{
auth-server-url: 'http://keycloak-server/auth',
realm: 'myrealm',
resource: 'myapp'
}
and not
{
url: 'http://keycloak-server/auth',
realm: 'myrealm',
clientId: 'myapp'
}

Related

nuxt auth : Google provider return invalid_request

I try to set google authentication with Nuxt Auth module, but I got following error from google:
Error 400 : invalid_request
Parameter not allowed for this message type: nonce
Here is my config
// nuxt.config.js
modules: ["#nuxtjs/axios", "#nuxtjs/auth-next"],
auth: {
router: {
middleware: ["auth"],
},
redirect: {
login: "/login",
logout: "/",
callback: false,
home: "/",
},
strategies: {
google: { clientId: "MyClientID", codeChallengeMethod: "" }
}
}
And how i call the google auth in my component:
login(){
this.$auth.loginWith("google").then( result => console.log(result) )
}
I also try to run official demo from here:
https://github.com/nuxt-community/auth-module/tree/dev/demo
But I got the same error.
Had the same issue but setting responseType: 'code' worked for me.
EDIT: Set responseType: "id_token token" for an implicit grant flow and to get redirected to your Nuxt app with an access token by Google. This whole OAuth topic has always been quite confusing to me and there's so much misinformation out there on what to do and what not to do in terms of security. I have found the following article to be very helpful and demystify the various OAuth flows: https://itnext.io/an-oauth-2-0-introduction-for-beginners-6e386b19f7a9 However if you do not want to expose the access token on the front end and rather obtain it in your back end then you must use the code grant flow by setting responseType: "code" and set up your back end properly. I ended up using the code grant flow but I assume that most people find the implicit grant flow more convenient.
Here's the full snippet:
export default {
modules: ["#nuxtjs/axios", "#nuxtjs/auth-next"],
auth: {
strategies: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID,
redirectUri: `${process.env.BASE_URL}/auth/google/callback`,
codeChallengeMethod: "",
responseType: "id_token token",
},
},
},
router: {
middleware: ["auth"],
},
};
Seems to be related with the version of Nuxt Auth.
Maybe this feature is not ready in #nuxtjs/auth-next
So i run
npm install #nuxtjs/auth#latest --save
Then update nuxt.config.json
replace #nuxtjs/auth-next with #nuxtjs/auth
replace clientId with client_id
// nuxt.config.js
modules: ["#nuxtjs/axios", "#nuxtjs/auth"],
auth: {
router: {
middleware: ["auth"],
},
redirect: {
login: "/login",
logout: "/",
callback: false,
home: "/",
},
strategies: {
google: { client_id: "MyClientID"}
}
}
in auth-next and auth0 the setting of responseType let me bypass the problem, my working config looks like:
auth0: {
logoutRedirectUri: process.env.BASE_URL,
domain: String(process.env.AUTH0_DOMAIN).replace(/(^\w+:|^)\/\//, ''),
clientId: process.env.AUTH0_CLIENT_ID,
scope: ['read:reports', 'read:roles', 'create:client_grants', 'offline_access'], // 'openid', 'profile', 'email' default added
audience: process.env.AUTH0_AUDIENCE,
responseType: 'token',
accessType: 'offline',
grantType: 'client_credentials',
redirectUri: process.env.BASE_URL + '/callback',
codeChallengeMethod: 'S256'
}

Azure OAuth with Cypress: Infinite Loop

Trying to set up Cypress to test an application that uses OAuth against Azure AD. My login command is defined as follows:
Cypress.Commands.add('login', () => {
return cy.request('POST', Cypress.env('AccessTokenUrl') +
'?grant_type=' + Cypress.env('GrantType') +
'&client_id=' + Cypress.env('ClientId') +
'&client_secret=' + Cypress.env('ClientSecret'))
})
This is what I call in a test:
cy.login().then(response => {
expect(response.status).to.eq(200)
expect(response.body).to.have.property('access_token')
expect(response.body).to.have.property('token_type', 'Bearer')
const {access_token, expires_in, id_token} = response.body
cy.setCookie('access_token', access_token)
})
cy.visit('my-url')
The validations pass. The login response contains a valid token. However, the ct.visit call fails with infinite recursion, as the parameters like &iframe-request-id=[some uuid] become added over and over to a login.microsoftonline.com URL, until eventually returning HTTP Error 414. The request URL is too long.
Here's what the URL looks like, with some information redacted and with some formatting for clarity:
https://login.microsoftonline.com/
[tenant-id]/oauth2/v2.0/authorize
?response_type=code
&client_id=[client-id]
&redirect_uri=[my-url]
&scope=openid+profile+email+https%3A%2F%2Fgraph.microsoft.com%2Fuser.read
&iframe-request-id=1a9fdcbd-6b9e-46c8-93e3-ce0edf62b600
&iframe-request-id=b5b5cf2b-e0a6-4d92-9e55-cf32208ab900
&iframe-request-id=8471e17f-1d36-48f7-8419-f54e14b3b100
&iframe-request-id=56113dad-6029-4a37-9758-5828f93f0300
&iframe-request-id=51c06224-98f1-4b83-a8f2-84f8dfe9aa00
&iframe-request-id=09775645-505c-42e0-ac56-1335b5a7ba00
&iframe-request-id=5c98158b-b202-41fe-9d65-8fbfe4e46500
&[and-so-on]
I have found various suggestions on the web about using Puppeteer as a task for Azure AD SSO, but none of them works for my purposes. First, they try to resolve the problem of actually obtaining the token, which I have already solved. Second, they rely on the login URL presenting an HTML form, which is not the case with login.microsoftonline.com.
What do you suggest?
UPDATE: Trying a different solution, I receive an interesting error. The loginMS command:
import * as MSAL from '#azure/msal-browser'
Cypress.Commands.add('loginMS', () => {
cy.request({
method: 'POST',
url: `https://login.microsoftonline.com/${Cypress.env('TenantId')}/oauth2/token`,
form: true,
body: {
scope: Cypress.env('LoginScope'),
client_id: Cypress.env('ClientId'),
client_secret: Cypress.env('ClientSecret'),
redirect_uri: Cypress.env('LoginRedirect'),
grant_type: Cypress.env('GrantType'),
username: Cypress.env('Username'),
password: Cypress.env('Password'),
response_type: 'code'
}
}).then(response => {
console.log(response)
window.localStorage.setItem(`msal.idtoken`, response.body.access_token);
window.localStorage.setItem(`msal.client.info`, MSAL.clientInfo);
})
})
The error is:
Failed to find a valid digest in the 'integrity' attribute for resource
'https://aadcdn.msauth.net/shared/1.0/content/js/OldConvergedLogin_PCore_Up8WrFIk8-TG_eqBz8MSlw2.js'
with computed SHA-256 integrity 'NxfOkHjbTYDy/EOknsK0PMOfym7iLRGY+yBShyznzx4='.
The resource has been blocked.
It realy depends how the application under test handles requests. But I guess you use the adal libary.
With the help of https://mechanicalrock.github.io/2020/05/05/azure-ad-authentication-cypress.html it worked for me in a vuejs application using adal v1.
The important part is
localStorage.setItem("adal.token.keys", `${Cypress.config("clientId")}|`);
localStorage.setItem(`adal.access.token.key${Cypress.config("clientId")}`, ADALToken);
localStorage.setItem(`adal.expiration.key${Cypress.config("clientId")}`, expiresOn);
localStorage.setItem("adal.idtoken", ADALToken);
I actually did not request the token from azure but just copied in what I saw F12 tools as my token when using the application under test.
I managed to solve the Azure AD login by creating the following Cypress custom command for my Angular application:
Cypress.Commands.add('login', () => {
return cy
.request({
method: 'POST',
url: `https://login.microsoftonline.com/${tenantId}/oauth2/token`,
form: true,
body: {
grant_type: 'password',
tenant: 'tenantId',
client_id: 'clientId',
client_secret: 'clientSecret',
username: 'username',
password: 'password',
resource: 'clientId',
},
})
.then((response) => {
sessionStorage.setItem('access_token', response.body.access_token);
});
});

Using StackTrace.js with Angular.js

I'm implementing a logger for my whole MEAN.js project. I have a server side logger that works well, and I've set an endpoint to receive a POST request with an exception to log a client error. I'm using StackTrace.js for client side error logging, but I'm getting some errors; now I'm using StackTrace's error-stack-parser and still getting errors. I'm using a decorator on Angular's $exceptionHandler to achieve this:
$provide.decorator("$exceptionHandler",
function($delegate, traceService, $log, $window) {
return function(exception, cause) {
$delegate(exception, cause);
try {
var errorMessage = exception.toString();
var stackTrace = traceService.
parse(exception).
then(function(stackFrames) {
$.ajax({
type: 'POST',
url: '/logger',
contentType: 'application/json',
data: angular.toJson({
url: $window.location.href,
message: errorMessage,
type: 'exception',
stackFrace: stackFrames,
cause: cause || ''
})
}).fail(function() {
$log.warn('POST request failed');
});
}).catch(function(error) {
$log.warn('Error StackTrace');
});
} catch (loggingError) {
$log.warn('Error server-side logging failed');
$log.log(loggingError);
}
};
});
traceService is an Angular service that acts as a proxy for StackTrace/error-stack-parser functions. traceService.parse is equivalent to ErrorStackParser.parse. traceService is implemented as:
angular.module('core').factory('traceService', function() {
return {
parse: ErrorStackParser.parse
};
});
I've put this decorator code on the Angular app bootstrap, and I'm testing by throwing an error on a controller. When I run the app I get this error on the client console:
Error server-side logging failed
angular.js:13708 TypeError: this.parseV8OrIE is not a function
at Object.ErrorStackParser$$parse [as parse] (error-stack-parser.js:70)
at application.js:22
at invokeLinkFn (angular.js:9816)
at nodeLinkFn (angular.js:9215)
at compositeLinkFn (angular.js:8510)
at publicLinkFn (angular.js:8390)
at lazyCompilation (angular.js:8728)
at updateView (viewDirective.ts:278)
at Object.configUpdatedCallback [as configUpdated] (viewDirective.ts:226)
at configureUiView (view.ts:164)
It would seem like this is an issue with error-stack-parse; I can't seem to find any articles regarding this issue, so I'm sure it's something I'm doing wrong, the way I'm testing or something else. Can any provide some insight as to why this is failing?
Edit
I modified the code following Caramiriel's comment. It seems like I need to add all functions from error-stack-parser to my service. This is traceService:
angular.module('core').factory('traceService', function() {
return {
parse: ErrorStackParser.parse,
parseV8OrIE: ErrorStackParser.parseV8OrIE,
extractLocation: ErrorStackParser.extractLocation
};
});
Now I'm getting this error:
TypeError: StackFrame is not a constructor
at Object.<anonymous> (http://localhost:3000/lib/error-stack-parser/error-stack-parser.js:105:24)
at Array.map (native)
at _map (http://localhost:3000/lib/error-stack-parser/error-stack-parser.js:22:26)
at Object.ErrorStackParser$$parseV8OrIE [as parseV8OrIE] (http://localhost:3000/lib/error-stack-parser/error-stack-parser.js:95:20)
at Object.ErrorStackParser$$parse [as parse] (http://localhost:3000/lib/error-stack-parser/error-stack-parser.js:70:29)
at http://localhost:3000/application.js:22:11
at invokeLinkFn (http://localhost:3000/lib/angular/angular.js:9816:9)
at nodeLinkFn (http://localhost:3000/lib/angular/angular.js:9215:11)
at compositeLinkFn (http://localhost:3000/lib/angular/angular.js:8510:13)
at publicLinkFn (http://localhost:3000/lib/angular/angular.js:8390:30)
It looks like you are using error-stack-parser without its dependency on the stackframe project.
You'll get that dependency automatically if you use npm or bower.

Google oauth satellizer 404 Error

This is my code. I am using authenticate('google'). After clicking on allow button I get error 404.
I am using satellizer.js for google authentication.
Please help me if you understand this error.
Error in browser
POST http://localhost:8080/auth/google 404 (Not Found)
Object {data: "Cannot POST /auth/google↵", status: 404, config: Object, statusText: "Not Found"}
Inside controller
$scope.authenticate = function (provider) {
$auth.link(provider)
.then(function(response) {
// You have successfully linked an account.
console.log(response);
})
.catch(function(response) {
// Handle errors here.
console.log('----------error--------')
console.log(response);
});
};
My code inside app.js
$authProvider.google({
clientId: 'xxxxxxxxxx2op4madn.apps.googleusercontent.com'
});
$authProvider.google({
url: '/auth/google',
authorizationEndpoint: 'https://accounts.google.com/o/oauth2/auth',
redirectUri: window.location.origin || window.location.protocol + '//' + window.location.host,
requiredUrlParams: ['scope'],
optionalUrlParams: ['display'],
scope: ['profile', 'email'],
scopePrefix: 'openid',
scopeDelimiter: ' ',
display: 'popup',
type: '2.0',
popupOptions: {width: 452, height: 633}
});
I got the issue actually it's find a post request on that URL you can add some configuration inside you server.js file follow this given GIT-URL.
github satellizer

CompoundJS and passport support

I'm facing this problem with compound passport. I've already followed the steps from the guide but I cannot get this working when I try to access /auth/github.
Any tips?
GET /auth/github controller: auth action: github
Params: {"controller":"auth","action":"github"}
>>> perform github
Error: Undefined action auth#github(/auth/github)
at Object.FlowControl.call.context.innerNext (/Users/javiermanzanomorilla/Development/workspace/authapp/node_modules/compound/node_modules/kontroller/lib/flow-control.js:67:27)
at Array.FlowControl.call.collection.forEach.queue.push.ctl.context.inAction [as 1] (/Users/javiermanzanomorilla/Development/workspace/authapp/node_modules/compound/node_modules/kontroller/lib/flow-control.js:139:28)
at run (/Users/javiermanzanomorilla/Development/workspace/authapp/node_modules/compound/node_modules/kontroller/lib/flow-control.js:102:27)
at Array.FlowControl.call.action [as 0] (/Users/javiermanzanomorilla/Development/workspace/authapp/node_modules/compound/node_modules/kontroller/lib/flow-control.js:60:13)
at run (/Users/javiermanzanomorilla/Development/workspace/authapp/node_modules/compound/node_modules/kontroller/lib/flow-control.js:102:27)
at FlowControl.call.compiledAction.(anonymous function) (/Users/javiermanzanomorilla/Development/workspace/authapp/node_modules/compound/node_modules/kontroller/lib/flow-control.js:90:9)
at Controller.call (/Users/javiermanzanomorilla/Development/workspace/authapp/node_modules/compound/node_modules/kontroller/lib/flow-control.js:49:16)
at Controller.call (/Users/javiermanzanomorilla/Development/workspace/authapp/node_modules/compound/node_modules/kontroller/lib/flow-control.js:93:10)
at Controller.perform (/Users/javiermanzanomorilla/Development/workspace/authapp/node_modules/compound/node_modules/kontroller/lib/flow-control.js:18:10)
at ControllerBrigde.callControllerAction (/Users/javiermanzanomorilla/Development/workspace/authapp/node_modules/compound/lib/controller-bridge.js:95:9)
i think that you havn't init the passport.
if you are using compound-passport you have to initialize it by calling the init function in config/environment.
var pass_connect=require('compound-passport');
app.configure(function(){
....
//init the compound passport
pass_connect.init(compound);
app.use(app.router);
});
case if you want to initialize it manualy you have to call those two methods :
var passport=require('passport');
var Strategy = require('passport-github').Strategy;
passport.use(new Strategy({
clientID: conf.github.clientID,
clientSecret: conf.github.secret,
callbackURL: conf.baseURL + 'auth/github/callback'
}, exports.callback));
app.get('/auth/github',
passport.authenticate('github'));
app.get('/auth/github/callback',
passport.authenticate('github', { failureRedirect: '/' }),
exports.redirectOnSuccess);
sorry for my english.

Categories

Resources