Okta signout don't work in Angular Applicaiton - okta

I am using OKTA SDK for the angular following enter link description here
this documentation. I am also using OktaCallbackComponent and OktaAuthService for authentication.
I can log in successfully. after a successful login OKTA redirects me to OktaCallbackComponent where they store some keys in localstroge and finally, I get navigated to my main page.
now when I click on the logout button from the application it does not work. As I see it the page loads and immediately navigates to the callback component and again navigates to the main page. whereas I want the login page should come to the user.
this is my logout function.
async logout(){
this.oktaAuth.tokenManager.clear()
await this.oktaAuth.signOut();
this.router.navigate(['/login']);
this.toastr.success('Logout Successfully', 'See you next time' , {timeOut: 5000});
}
can anyone help me with what could be the issue.
{
path: 'main',
component: OpDataTableComponent,
canActivate: [ OktaAuthGuard ],
data: {
title: 'Main Page'
}
},
{
path: CALLBACK_PATH,
component: OktaCallbackComponent,
// Later: Add a component
},
{
path: 'login',
// component: LoginComponent,
component:OktaLoginComponent,
canActivate: [checkAfterLoginService],
data: {
title: 'Login Page'
}
}
CheckAfterLoginService
export class checkAfterLoginService {
constructor(private oktaAuth: OktaAuthService,private tokenService: TokenService, private router: Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> {
if(this.oktaAuth.isAuthenticated())
{
return this.router.navigateByUrl('/main');
}else
{
return false;
}
}
}
Okta configuration.
const ISSUER = 'https://...../oauth2/default';
const HOST = window.location.host;
const REDIRECT_URI = 'https://..../callback';
const SCOPES = 'openid profile email';
const config = {
issuer: ISSUER,
clientId: '.....',
redirectUri: REDIRECT_URI,
scopes: SCOPES.split(/\s+/)
};
P.s logout URL added to the application setting is https://../login route.
how can I solve the issue or what could be the issue? your help is much appreciated.

Try changing your logout() method to be as follows:
async logout(){
await this.oktaAuth.signOut();
this.router.navigate(['/login']);
this.toastr.success('Logout Successfully', 'See you next time' , {timeOut: 5000});
}
You're currently clearing the tokens manually, which makes our underlying Auth JS SDK thinking you've already logged out. this.oktaAuth.signOut() should clean up the tokens for you. If you still want to clear them manually, make sure and do it after signOut().

I had similar issues, but I wanted to redirect back to the okta login screen. This is what worked for my situation.
public logout(): void {
const oktaBaseUrl: string = `${environment.okta.issuer}/v1`;
const oktaTokenStorage: any = JSON.parse(localStorage.getItem('okta-token-storage'));
const oktaIdToken = oktaTokenStorage?.idToken;
this.oktaAuth.logout();
window.location.href = `${oktaBaseUrl}/logout?id_token_hint=${oktaIdToken.idToken}&post_logout_redirect_uri=${environment.okta.postLogoutRedirectUri}`;
}

Related

Strapi returns 404 for custom route only when deployed to Heroku

I have created a custom route in Strapi v4 called "user-screens". Locally I hit it with my FE code and it returns some data as expected. However when I deploy it to Heroku and attempt to access the endpoint with code also deployed to Heroku it returns a 404. I've tailed the Heroku logs and can see that the endpoint is hit on the server side, but the logs don't give anymore info other than it returned a 404.
I am doing other non custom route api calls and these all work fine on Heroku. I am able to auth, save the token, and hit the api with the JWT token and all other endpoints return data. This is only happening on my custom route when deployed to Heroku. I've set up cors with the appropriate origins, and I am wondering if I need to add something to my policies and middlewares in the custom route. I have verified the permissions and verified the route is accessible to authenticated users in the Strapi admin.
Here is my route:
module.exports = {
routes: [
{
method: "GET",
path: "/user-screens",
handler: "user-screens.getUserScreens",
config: {
policies: [],
middlewares: [],
},
},
],
};
And my controller:
"use strict";
/**
* A set of functions called "actions" for `user-screens`
*/
module.exports = {
getUserScreens: async (ctx) => {
const user = ctx.state.user;
if (!user) {
return ctx.badRequest(null, [
{ messages: [{ id: "No authorization header was found" }] },
]);
}
strapi.entityService
.findMany("api::screen.screen", {
owner: user.id,
populate: ["image"],
})
.then((result) => {
ctx.send(result);
});
},
};
For anyone facing this, the answer was to change how I returned the ctx response from a 'send' to a 'return' from the controller method. I am not sure why this works locally and not on Heroku, but this fixes it:
New controller code:
module.exports = {
getUserScreens: async (ctx) => {
const user = ctx.state.user;
if (!user) {
return ctx.badRequest(null, [
{ messages: [{ id: "No authorization header was found" }] },
]);
}
return strapi.entityService
.findMany("api::screen.screen", {
owner: user.id,
populate: ["image"],
})
.then((result) => {
return result;
})
.catch((error) => {
return error;
});
},
};

calling back-end api (laravel) from getServerSideProps() in next js

I am using next js as a front-end and laravel as a back-end. and i want to call back-end (laravel) api from getServerSideProps() method. as shown below
export async function getServerSideProps(context) {
const response = await Axios.request({
url: 'http://localhost:8000/api/event',
method: 'get',
headers: {
Cookie: context.req.headers.cookie,
},
})
const events = response.events
console.log(response)
return {
props: { events },
}
}
so i have also set the cookie but i am getting response with message unauthenticated like below
I just wanted to say a huge THANK YOU to Riaz Kahn for his answer. After a lot of banging my face against a wall this was the answer. I'm going to post a working example of my getServerSideProps function for anyone arriving here in the future. The getUser({[configObject]}) function is just returning a promise from an axios.get('my-user/route', config) call. This is working properly in a Next 13 app using standard pages functionality (not using experimental app directory).
export const getServerSideProps = async (context: any) => {
const {req, res} = context;
try {
const {data: user} = await getUser({
headers: {...req.headers}
});
return {
props: {
fallback: {user}
}
}
} catch (e) {
res.writeHead(302, {Location: '/login'});
res.end();
}
}

Inject token from auth0 to React-admin Hasura data provider

This example demonstrates how to use Auth0 with react-admin. It is working as expected.
We are trying to adjust it so it will use the hasura data provider. We've created a new file dataProvider.js that will construct the data-provider:
import buildHasuraProvider from "ra-data-hasura";
import { ApolloClient, InMemoryCache } from "#apollo/client";
export const initDataProvider = async (token) => {
const client = new ApolloClient({
uri: process.env.REACT_APP_GRAPHQL_URI,
headers: {
Authorization: `Bearer ${token}`,
},
cache: new InMemoryCache(),
});
const dataProvider = await buildHasuraProvider({ client });
return dataProvider;
};
However, we are missing the JWT token which is created as part of the Auth0 authentication process. We do not know how to get the token in order to initialize the data provider with it. Does react-admin know how to do it on its own? if not, how do we access the JWT token to do it ourselves manually?
This is the authProvider source-code:
import authConfig from "./authConfig";
import {Auth0Client} from '#auth0/auth0-spa-js';
const auth0 = new Auth0Client({
domain: authConfig.domain,
client_id: authConfig.clientID,
redirect_uri: authConfig.redirectURI,
cacheLocation: 'localstorage',
useRefreshTokens: true
});
export default {
// called when the user attempts to log in
login: (url) => {
if (typeof url === 'undefined') {
return auth0.loginWithRedirect()
}
return auth0.handleRedirectCallback(url.location);
},
// called when the user clicks on the logout button
logout: () => {
return auth0.isAuthenticated().then(function (isAuthenticated) {
if (isAuthenticated) { // need to check for this as react-admin calls logout in case checkAuth failed
return auth0.logout({
redirect_uri: window.location.origin,
federated: true // have to be enabled to invalidate refresh token
});
}
return Promise.resolve()
})
},
// called when the API returns an error
checkError: ({status}) => {
if (status === 401 || status === 403) {
return Promise.reject();
}
return Promise.resolve();
},
// called when the user navigates to a new location, to check for authentication
checkAuth: () => {
return auth0.isAuthenticated().then(function (isAuthenticated) {
if (isAuthenticated) {
return Promise.resolve();
}
return auth0.getTokenSilently()
})
},
// called when the user navigates to a new location, to check for permissions / roles
getPermissions: () => {
return Promise.resolve()
},
};
It is unclear to us if there is a point where we can extract the token from.
getTokenSilently should give you back the token.
You'll have to structure your React app such that you have access to the result of this method before you construct your data provider.

AngularFireAuthGuard redirectUrl after login

I use firebase and AngularFireAuthGuard to protect specific routes, so that only authenticated users are allowed to access them.
In particular, my MainComponent and MgmtComponent should only be accessible to AUTHENTICATED users.
const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['/login']);
const routes: Routes = [
{ path: 'teams/:teamId/sessions/:sessionId',
component: MainComponent,
canActivate: [AngularFireAuthGuard], data: { authGuardPipe: redirectUnauthorizedToLogin }
},
{ path: 'mgmt',
component: MgmtComponent,
canActivate: [AngularFireAuthGuard], data: { authGuardPipe: redirectUnauthorizedToLogin }
},
{
path: 'login',
component: LoginComponent
}
];
My Problem is, that the user is not redirected back to the originally requested URL, after a successful login.
So what I want/expect is:
user goes to /mgmt
as the user is not authenticated he is automatically redirected to /login
user authenticates (e.g. via google or Facebook OAuth)
user is automatically redirected back to the originally requested page (/mgmt)
Steps 1-3 work fine, but step 4 is missing.
Now that the feature request is in, you can do this using the auth guard. However, the docs are unclear, so here is how I did it.
/** add redirect URL to login */
const redirectUnauthorizedToLogin = (next: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
return redirectUnauthorizedTo(`/login?redirectTo=${state.url}`);
};
/** Uses the redirectTo query parameter if available to redirect logged in users, or defaults to '/' */
const redirectLoggedInToPreviousPage = (next: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
let redirectUrl = '/';
try {
const redirectToUrl = new URL(state.url, location.origin);
const params = new URLSearchParams(redirectToUrl.search);
redirectUrl = params.get('redirectTo') || '/';
} catch (err) {
// invalid URL
}
return redirectLoggedInTo(redirectUrl);
};
This is an open feature request, the angularfire team is working on it: https://github.com/angular/angularfire/pull/2448
Meanwhile I found this workaround:
In the app-routing-module.ts instead of
const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['/login']);
I use following to store the url in the sessionStorage:
const redirectUnauthorizedToLogin = (route: ActivatedRouteSnapshot) => {
const path = route.pathFromRoot.map(v => v.url.map(segment => segment.toString()).join('/')).join('/');
return pipe(
loggedIn,
tap((isLoggedIn) => {
if (!isLoggedIn) {
console.log('Saving afterLogin path', path);
sessionStorage.setItem('afterLogin', path);
}
}),
map(loggedIn => loggedIn || ['/login'])
);
};
In the LoginComponent I read the value from the session storage to redirect:
sessionStorage.getItem('afterLogin');
this.router.navigateByUrl(redirectUrl);

How to fix localhost:8000 prompt login after i submit the authentication using Vue Js And Laravel

I have problem regarding on my authentication after I login there is prompt localhost:8000 login or Sign in, this is the first time I encounter this, I don't know what this called, i don't find any reference for this. currently I am using laravel for the backend and vue js for front end. so this project created by old developer. so now I need to revise some module on there project, however i Login on the system in shows this prompt. note that this project is currently working and there is no error and prompt login when I login.
Here is prompt sign shown after I login.
Configuration:
Laravel Passport
Vuex For State Management
Vue Js
METHOD:
methods:{
authenticate(){
this.login_alert = false
this.$validator.validateAll().then((result)=>{
if(result){
const self = this;
const authUser = {}
try{
const data = {
username: this.email,
password: this.password,
remember: this.remember_me,
client_id: '2',
client_secret: 'just secret only',
grant_type : 'password',
scope : ''
}
this.$store.dispatch('AUTH_REQUEST',data)
.then(response=>{
authUser.access_token = response.access_token
authUser.refresh_token = response.refresh_token
authUser.expires_in = response.expires_in
window.localStorage.setItem('project_token',JSON.stringify(authUser))
/*LOGIN*/
this.login_alert = false
this.loading = false
window.location.reload()
})
.catch(error=>{
this.login_alert = true
window.localStorage.removeItem('project_token')
this.loading = false
})
}catch(err){
console.log(err);
}
}
})
}
},
AUTH REQUEST:
AUTH_REQUEST:({commit,dispatch},obj)=>{
return new Promise((resolve,reject) => {
axios({
url: '/oauth/token',
data: obj,
method:'post',
config:'JSON'
})
.then(response=>{
if(response.status == 200){
resolve(response.data);
}
})
.catch(error=>{
reject(error);
localStorage.removeItem('project_token');
commit('AUTH_ERROR',error);
})
})
},
Hope someone can help me to solve this problem.
Thank you.

Resources