Session timeout using SPA and oidc-js - identityserver4

I am using angular 5 with oidc-client and identity server 4. Is session timeout supported in oidc-client or i need to implement it manually ?
By Session Timeout i mean, the user will be logged out after sometime of inactivity

for your SPA applications you can use the implicit flow, refresh token is not possible automatically but oidc-client.js can make it easy for you. you can use the silent refresh, oidc-client will send the active cookie session to get a new access_token just before the expiration of the new one. you need only to configure it
const config = {
authority: xxxxx,
client_id: xxxxx,
popup_redirect_uri: `${OidcConfig.clientRoot}/assets/html/popup-login-redirect.html`,
scope: 'openid profile',
response_type: 'id_token token',
post_logout_redirect_uri: `${OidcConfig.clientRoot}?postLogout=true`, // delet all stored tokens after logout
userStore: new WebStorageStateStore({ store: window.localStorage }),
automaticSilentRenew: true, // enable silent refresh
silent_redirect_uri: `${OidcConfig.clientRoot}/assets/html/silent-refresh-redirect.html` // here when you can get the new tokens
};
here is the content of silent-refresh-redirect.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/oidc-client/1.5.1/oidc-client.min.js"></script>
<script>
var config = {
userStore: new Oidc.WebStorageStateStore({ store: window.localStorage })
};
new Oidc.UserManager(config).signinSilentCallback()
.catch((err) => {
console.log(err);
});
</script>

Related

"Authority mismatch on settings vs. signin state" with OIDC Client when trying to grant access between 2 client Applications

We have two .net core with angular applications where we have used Openid server and client
https://localhost:80 : Parent Application
https://localhost:85 : Child Application
We want to authenticate the child application within the parent application.
In the angular end, we used oidc-client and updated the UserManager dynamically inside the child application.
The flow we are trying to achieve is
Login Page child application (https://localhost:85) -> Click Login -> it redirects to parent app Login Page (https://localhost) -> entering credentials and After successful signing in the redirection URL will be (https://localhost:85) and it will grant access to that child application.
While redirecting to the child application by redirect URL after login it throws the below error "Authority mismatch on settings vs. signin state"
[![enter image description here][1]][1]
Can someone help me with the flow of authentication of multiple client applications via openid client ?
Error: authority mismatch on settings vs. signin state
at t [as _processSigninParams] (oidc-client.min.js:1:57198)
at t [as validateSigninResponse] oidc-client.min.js:1:55646)
at oidc-client.min. js:1:27449 at
ZoneDelegate. invoke (zone, js:372รท26) at Object.onInvoke (core.mjs:26356:33) at
ZoneDelegate. invoke (zone. js:371:52)
at Zone.run (zone. js:134:43)
at zone. js:1275:36 at
ZoneDelegate. invokeTask (zone. js:496:31)
at Object.onInvokeTask (core.mijs:26343:33)
Initially, the child application will have the below config
this.ChildAppConfig = {
authority: 'https://localhost',
client_id: 'child-spa',
redirect_uri: `https://localhost/signin-callback`,
scope: 'profile openid offline_access',
response_type: 'code',
post_logout_redirect_uri: `https://localhost/signout-callback`,
silent_redirect_uri: `https://localhost/silent-renew`,
automaticSilentRenew: false,
revokeAccessTokenOnSignout: true,
accessTokenExpiringNotificationTime: 60,
};
When I want to grant access to a child application via a parent application I will redirect it to the parent application, where the parent application will have the below config, and once authenticated it should redirect back to the child application
grantAccessConfig = {
authority: 'https://localhost:85',
client_id: 'spa',
redirect_uri: `https://localhost/signin-callback`,
scope: 'profile openid offline_access',
response_type: 'code',
post_logout_redirect_uri: `https://localhost/signout-callback`,
silent_redirect_uri: `https://localhost/silent-renew`,
automaticSilentRenew: false,
revokeAccessTokenOnSignout: true,
accessTokenExpiringNotificationTime: 60,
};
Ok i had this error before with Reactjs oidc-react and .net backend. the problem was that the configuration defined in SigninCallBack.js(here i init the storage and redirect) was not same as the configuration defined in identity server. this config was from the test app that throws that error
import React from 'react'
import { WebStorageStateStore } from 'oidc-client-ts';
import { UserManager } from 'oidc-react';
const SigninCallBack = () => {
var config = {
userStore: new WebStorageStateStore({store: window.localStorage}),
authority: "https://localhost:9001/",
client_id: "myappid",
redirect_uri: "https://localhost:3000/signincallback",
client_secret: "thesecretkey_but_i_used_PKCE",
response_type: "code",
scope:"openid profile someApi",
post_logout_redirect_uri : "https://localhost:3000/signout-callback-oidc",
loadUserInfo: true
};
var userManager = new UserManager(config);
userManager.signinCallback().then(res => {
window.location.href = '/';
});
}
export default SigninCallBack;
and mine was the client url which here i was defined with http but in the identityserver config i defined it with https. however it could be any of them such as response type ,client Id etc.

Silent Refresh - Refreshing Access Tokens when using the Implicit Flow is not working on custom login URL

I'm using IdentityServer4(.NET Core API) and 'oidc-client' in Angular, In which I'm using custom login and logout urls, not default identityserver4 urls, So in this scenario silent-refresh request from 'oidc-client'. it returns 302, Still token is getting expired after sometimes automatically
IdentityServer4:
services.AddIdentityServer(opt =>
{
opt.UserInteraction.LoginUrl = "/User/Login";
opt.UserInteraction.LogoutUrl = "/User/Logout";
opt.Events.RaiseErrorEvents = true;
opt.Events.RaiseFailureEvents = true;
opt.Events.RaiseInformationEvents = true;
opt.Events.RaiseSuccessEvents = true;
})
oidc-client:
getClientSettings(): UserManagerSettings {
return {
authority: localStorage.getItem('authorizationRoot'),
client_id: 'MileTMSAngapp',
redirect_uri: localStorage.getItem('redirectUri'),
post_logout_redirect_uri:
localStorage.getItem('postLogoutRedirectUri'),
response_type: 'id_token token',
scope: 'openid profile MileTMS',
filterProtocolClaims: false,
loadUserInfo: true,
automaticSilentRenew: true,
silent_redirect_uri: localStorage.getItem('silentRedirectUri')
};
}
'Silent-Callback':
return this.manager.signinSilentCallback()
.then(doSomething => 'done');
what kind of error are you seeing in the console?
With the minimal information that you have provided, my guess is that you are facing this issue. Hopefully, this helps.
IdentityServer Session cookie is not sliding

ValidateAntiForgeryToken blocking new login

I have an identity server 4 implementation very simple and I'm using the oidc-client on my angular APP to carry on all the security management. In my auth service I have the following:
#Injectable()
export class AuthService {
private manager: UserManager;
private user: User = null;
constructor() {
if (!environment.production) {
Log.logger = console;
}
this.manager = new UserManager(getClientSettings());
this.manager.getUser()
.then(user => {
this.user = user;
});
this.manager.events.addUserSignedOut(() => {
this.user = null;
this.signOut();
});
}
signOut(): Promise<void> {
return this.manager.signoutRedirect()
.then(() => {
this.manager.clearStaleState();
});
}
...more
}
export function getClientSettings(): UserManagerSettings {
return {
authority: environment.authorityUrl,
client_id: 'myclient',
redirect_uri: `${environment.baseUrl}/auth-callback`,
post_logout_redirect_uri: environment.baseUrl,
response_type: 'id_token token',
scope: 'openid profile myapi',
filterProtocolClaims: true,
loadUserInfo: true,
automaticSilentRenew: true,
revokeAccessTokenOnSignout : true,
silent_redirect_uri: `${environment.baseUrl}/silent-renew-callback`,
};
}
Everything works like a charm so I can log in/out without any issues, the token renewal works as expected and so far so good. However I decided to implement a "custom" behavior when a user open the application in multiple tabs on the same browser and one of them logs out. Then the event UserSignedOut is triggered and I sign out the rest of the tabs that may be open. The problem I have is that when the user comes back in, the FIRST login attempt is performed correctly, however any subsequent login request from any other tab results in a 400 - BAD REQUEST (removing the Antiforgery token attribute from the login method in my IS4 it then works but I don't want to do so).
If you did refresh the tab then you get logged in therefore to me it seems something wrong with the actual state itself?
I'm not sure if I should invoke any other method in my AuthService prior logging out or whether I should re-implement the ValidateAntiForgeryToken with a custom behavior for this.
Any help is much appreciated, thanks!

Issue on redux-oidc signoutRedirect

Question / Issue
I'm using Identity Server for Single Sign On, my Client application is in ReactJs embedded with Redux. I'm using redux-oidc npm node module to implement the Identity Server functionality as mentioned in https://github.com/IdentityModel/oidc-client-js/wiki
My oidc config is
var settings = {
authority: 'https://localhost:2025/core',
client_id: 'TVA',
silent_redirect_uri: 'http://localhost:3000/silent-renew.html',
post_logout_redirect_uri: 'http://localhost:3000',
redirect_uri: `http://localhost:3000/callback`,
response_type: 'id_token token',
scope: 'openid payroll',
acr_values: `tenant:Payroll`,
accessTokenExpiringNotificationTime: 4,
automaticSilentRenew: true,
filterProtocolClaims: true
};
If I use the in-built method signoutRedirect, its again redirecting to the application's initial landing page, but if I directly trigger the end session it redirects to the Identity Server Login Page (i.e., Once the application is successfully logout, the Identity Server redirects to the root URI and then it redirects to the Login page).
Issue: Its not Signout the application
userManager.signoutRedirect()
.catch(function (error) {
console.error('error while signing out user', error);
});
Fine: Signout's perfectly
const path = 'https://localhost:2025/core/connect/endsession?id_token_hint=${token}&post_logout_redirect_uri=http://localhost:3000';
document.location.href = path;
Kindly assist me how to signout using userManager.signoutRedirect() ???

callback missmatch error in angular with auth0

Hi I'm using Auth0 with Nodejs and angularjs
here is what i want to achieve
1. I want to user to signup using auth0's lock
2. as soon as user logs in a callback should be called at my nodejs server
3. after that i will get the user information and user's JWT
4. then i will redirect user to dashboard page and store the JWT in browser
What's the problem with Auth0's example
1. they provide example either for angular or nodejs standalone not the combined
2. there is combined(client server) example but that's using jade with nodejs
my code snipped
Angular snipped
var options = { auth: {
redirectUrl: 'http://localhost:3000/callback'
, responseType: 'code'
, params: {
scope: 'openid name email picture'
}
}
}
lockProvider.init({
clientID: 'cUlBNhhaIblahBlahRp6Km',
domain: 'rishabh.auth0.com',
option:options
});
node snipped
router.get('/callback',
passport.authenticate('auth0', { failureRedirect: '/url-if-something-fails' }),
function(req, res) {
console.log(req.user);
res.json({id_token:req.user});
});
Note: I've added this callbacks in auth0
http://localhost:3000/callback
but dont know why I'm facing this error for callback error when I've mentioned my redirect URL in angular side
can anyone tell me what is the problem with my code why auth0 not redirecting me to this url http://localhost:3000/callback
and the interesting thing is when i use simple lock.js instead of angular like this
<script>
var options = { auth: {
redirectUrl: 'http://localhost:3000/callback'
, responseType: 'code'
, params: {
scope: 'openid name email picture'
}
}
}
var lock = new Auth0Lock('clientID', 'rishabh.auth0.com',options);
lock.show();
</script>
then in this case my nodejs /callback route is called properly, so what I'm doing wrong with angular ?
please help
Update
this is my project structure
full code
https://github.com/LabN36/error
Config.js
var Auth0Strategy = require('passport-auth0');
var passport = require('passport');
var strategy = new Auth0Strategy({
domain: process.env.AUTH0_DOMAIN || 'rishabh.auth0.com',
clientID: process.env.AUTH0_CLIENT_ID || 'cUheWwRxm7OLdHBRzlBNvfvfvfvfvhhaI1lxRp6Km',
clientSecret: process.env.AUTH0_CLIENT_SECRET || 'e37eIZpjgBnDMBtrYMwvffvfvfvfaU4jSqt8qylZMT9Oj1EiffLGViinWQ5AiuWi1-WBwA8v3',
callbackURL: process.env.AUTH0_CALLBACK_URL || 'http://localhost:3000/callback'
}, function(accessToken, refreshToken, extraParams, profile, done) {
// accessToken is the token to call Auth0 API (not needed in the most cases)
// extraParams.id_token has the JSON Web Token
// profile has all the information from the user
console.log(extraParams.id_token);
//save user detail with token here and return token only profile
return done(null, extraParams.id_token);
});
passport.use(strategy);
// you can use this section to keep a smaller payload
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
module.exports = passport;
AngularApp.js
angular.module('workApp',['auth0.lock'])
.config(function($locationProvider,lockProvider){
var options = { auth: {
// redirect:true,
responseType: 'code',
redirectUrl: 'http://localhost:3000/callback',
params: {
scope: 'openid name email picture'
}
}
}
lockProvider.init({clientID: 'cUheWwRxm7OLdHBRzlBNhhaI1lxRp6Km',domain: 'rishabh.auth0.com',
option:options
});
$locationProvider.html5Mode(true);
})
.controller('homeCtrl',function($scope,$http,$location,$window,lock){
$scope.login = function() {
// window.alert("magic")
console.log("Messed Up really")
var vm = this;
vm.lock = lock;
lock.show();
}
}).run(function(lock){
lock.interceptHash();
lock.on('authenticated', function(authResult) {
localStorage.setItem('id_token', authResult.idToken);
lock.getProfile(authResult.idToken, function(error, profile) {
if (error) {
console.log(error);
}
localStorage.setItem('profile', JSON.stringify(profile));
});
});
})
According to the screenshot the error happens because the authentication request is made with a redirect_uri of:
http://localhost:3000/
and the allowed callback URL's are:
http://localhost:3000/callback
http://35.162.118.253:3000/callback
Also based on the code you shared you're indeed setting the redirectUrl to be http://localhost:3000/callback so there may be something on the rest of the code that either causes that value to be overridden or not used at all.
If the redirectUrl is not set, Lock will use the current page so the likely culprit is that the options you set are not being used. If you still don't find the cause for this, update the question with the code associated with how Lock is shown.
Damn, the actual root cause was already shown in the code you initially provided, but only looking now at the full code made it possible for me to catch it...
You're calling lockProvider.init() with:
{ clientID: [?], domain: [?], option: options }
when it should be called with:
{ clientID: [?], domain: [?], options: options } // options instead of option

Resources