I am implementing auth0 to my angular project,
and I get the, error loading discovery document in my auth.config service "this.oauthService.loadDiscoveryDocumentAndLogin()",
as the auth0 page was not found.
Please, any help is welcome. Thank you.
This is my component, here I declare variables that call my auth0 data that I have in the env
I have some doubts about the logout route,
reviewing forums I have seen that others do not put /v2
export const authConfig: AuthConfig = {
issuer: environment.keycloak.issuer,
redirectUri: environment.keycloak.redirectUri,
clientId: environment.keycloak.clientId,
responseType: environment.keycloak.responseType,
scope: environment.keycloak.scope,
requireHttps: environment.keycloak.requireHttps,
showDebugInformation: environment.keycloak.showDebugInformation,
disableAtHashCheck: environment.keycloak.disableAtHashCheck,
customQueryParams: {
audience: environment.audience
},
logoutUrl : `${environment.keycloak.issuer}v2/logout?client_id=${environment.keycloak.clientId}&returnTo=${encodeURIComponent(environment.keycloak.redirectUri)}`
}
export class OAuthModuleConfig {
resourceServer: OAuthResourceServerConfig = {sendAccessToken: false};
}
export class OAuthResourceServerConfig {
allowedUrls?: Array<string>;
sendAccessToken = true;
customUrlValidation?: (url: string) => boolean;
}
this is my service, I get the error in this.oauthService.loadDiscoveryDocumentAndLogin()
#Injectable()
export class AuthConfigService {
private _decodedAccessToken: any;
private _decodedIDToken: any;
get decodedAccessToken() { return this._decodedAccessToken; }
get decodedIDToken() { return this._decodedIDToken; }
constructor(
private readonly oauthService: OAuthService,
private readonly authConfig: AuthConfig) { }
async initAuth(): Promise<any> {
return new Promise((resolveFn, rejectFn) => {
// setup oauthService
this.oauthService.configure(this.authConfig);
this.oauthService.tokenValidationHandler = new NullValidationHandler();
// subscribe to token events
this.oauthService.events.pipe(filter((e: any) => {
if(e.params && e.params.error_description == 'user is blocked') {
console.log('Usuario bloqueado');
//Pagina de usuario bloqueado.
}
return e.type === 'token_received';
})).subscribe(() => this.handleNewToken());
// disabling keycloak for now
// resolveFn();
// continue initializing app or redirect to login-page
console.log(this.oauthService.loadDiscoveryDocumentAndLogin())
this.oauthService.loadDiscoveryDocumentAndLogin().then(isLoggedIn => {
console.log("isloggi",isLoggedIn)
if (isLoggedIn) {
this.oauthService.setupAutomaticSilentRefresh();
// #ts-ignore
resolveFn();
} else {
this.oauthService.initImplicitFlow();
rejectFn();
}
});
});
}
private handleNewToken() {
this._decodedAccessToken = this.oauthService.getAccessToken();
this._decodedIDToken = this.oauthService.getIdToken();
}
Related
I want to list the student details calling the java api which have below response. I want the values from data which will have multiple values.Below is the method i am calling in component.ts class.
ngOnInit() {
this.loading = true
this.httpService.get('/student').subscribe(
result => {
console.log('received results');
this.loading = false;
this.scouts = result;
},
error => {
console.log('failed');
this.loading = false;
}
``
This is the api response.
``
{
data: [
{
id: 101,
name: "John doe",
status: "enrolled",
}
],
errors: [ ],
warnings: [ ],
meta: { }
}
```
I tried to using this as html code but this won't work and in the component part i have called the httpservice with get request in ngOnInit part.
``
<tr *ngFor="let student of students">
<td>{{student.id}}</td>
<td>{{student.name}}</td>
<td>{{student.status}}</td>
```
Please can you guide me how can i get the student details from data part and list it in front end. Thank you.
From Best practices:
Use url at the service level (since it's a constant used only inside the service)
Define a StudentResponce model so that you can your json response.
Define the Student model that will be a property of StudentReponse
then your component becomes
ngOnInit() {
this.loading = true;
this.httpService.getStudents().subscribe(
result => {
console.log('received results');
this.loading = false;
this.scouts = result.data;
/*or this.scouts = [...result.data] */
//warning = result.warning
//meta = result.meta
//errors = [...result.errors]
},
error => {
console.log('failed');
this.message = error.message;
this.loading = false;
});
}
and the service
const url = "http://replace_with_service_url";
#Injectable()
export class MyHttpService {
constructor(private client: HttpClient) {
}
getStudents(): Observable<StudentResponse>{
return this.client.get<StudentResponse>(url);
}
}
export class StudentResponse{
data: Student[];
warning: any;
errors: any[];
meta: any;
}
export class Student{
id: number;
name= "";
status: string /*or enum "enrolled"*/;
}
you can replace your service url in this code to test
Just change this assignment:
this.scouts = result;
to
this.scouts = result.data;
i have an angular basic project and a simple microservice jhipster project. since i chosed jwt option in my jhipster project , i want to consume methods from my angular project.after looking for hours i finnaly found this code which helped me to connect successfuly but i get a weird error which bloked me. here is my angular classes i used to try connect and consume jhipster methods:
auth-interceptor.ts file
#Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private token: TokenStorageService) { }
intercept(req: HttpRequest<any>, next: HttpHandler) {
let authReq = req;
const token = this.token.getToken();
if (token != null) {
authReq = req.clone({ headers: req.headers.set(TOKEN_HEADER_KEY, 'Bearer ' + token) });
}
return next.handle(authReq);
}
}
export const httpInterceptorProviders = [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
];
auth.service.ts
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
#Injectable({
providedIn: 'root'
})
export class AuthService {
private loginUrl = 'http://localhost:8082/api/authenticate';
private signupUrl = 'http://localhost:8080/api/auth/signup';
constructor(private http: HttpClient) {
}
attemptAuth(credentials: AuthLoginInfo): Observable<JwtResponse> {
return this.http.post<JwtResponse>(this.loginUrl, credentials, httpOptions);
}
signUp(info: SignUpInfo): Observable<string> {
return this.http.post<string>(this.signupUrl, info, httpOptions);
}
}
jwt-response.ts
export class JwtResponse {
accessToken: string;
type: string;
username: string;
authorities: string[];
}
token-storage.service.spec.ts
describe('TokenStorageService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [TokenStorageService]
});
});
it('should be created', inject([TokenStorageService], (service: TokenStorageService) => {
expect(service).toBeTruthy();
}));
});
token.storage.service.ts
const TOKEN_KEY = 'AuthToken';
const USERNAME_KEY = 'AuthUsername';
const AUTHORITIES_KEY = 'AuthAuthorities';
#Injectable({
providedIn: 'root'
})
export class TokenStorageService {
private roles: Array<string> = [];
constructor() { }
signOut() {
window.sessionStorage.clear();
}
public saveToken(token: string) {
window.sessionStorage.removeItem(TOKEN_KEY);
window.sessionStorage.setItem(TOKEN_KEY, token);
}
public getToken(): string {
return sessionStorage.getItem(TOKEN_KEY);
}
public saveUsername(username: string) {
window.sessionStorage.removeItem(USERNAME_KEY);
window.sessionStorage.setItem(USERNAME_KEY, username);
}
public getUsername(): string {
return sessionStorage.getItem(USERNAME_KEY);
}
public saveAuthorities(authorities: string[]) {
window.sessionStorage.removeItem(AUTHORITIES_KEY);
window.sessionStorage.setItem(AUTHORITIES_KEY, JSON.stringify(authorities));
}
public getAuthorities(): string[] {
this.roles = [];
if (sessionStorage.getItem(TOKEN_KEY)) {
JSON.parse(sessionStorage.getItem(AUTHORITIES_KEY)).forEach(authority => {
this.roles.push(authority.authority);
});
}
return this.roles;
}
}
and finnaly this is my connection method:
onSubmit() {
console.log(this.form);
this.loginInfo = new AuthLoginInfo(
this.form.username,
this.form.password);
this.authService.attemptAuth(this.loginInfo).subscribe(
data => {
this.tokenStorage.saveToken(data.accessToken);
this.tokenStorage.saveUsername(data.username);
this.tokenStorage.saveAuthorities(data.authorities);
this.isLoginFailed = false;
this.isLoggedIn = true;
this.roles = this.tokenStorage.getAuthorities();
this.reloadPage();
},
error => {
console.log(error);
this.errorMessage = error.error.message;
this.isLoginFailed = true;
}
);
}
with this i am able to login successfully but once i login i get this error when i try to do anything else:
core.js:6014 ERROR SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse (<anonymous>)
at TokenStorageService.getAuthorities (token-storage.service.ts:45)
Guys if u know any simple method to connect to jhipster using jwt from angular please help me cause i am blocked here , i have a full jhipster project which i cant consume any..
Well, seems your server does not provide authorities in the JWT response. Since the data is missing, the saveAuthorities saves string "undefined" that cannot be served later.
If the reason authorities is missing is that you blindly copied some random code off the internet, delete the authorities from class JwtResponse and saveAuthorities, getAuthorities and all references to them.
Otherwise, just provide the authorities in your response.
Or you can check if authorities exist when saving them in onSubmit callback.
if (data.authorities)
this.tokenStorage.saveAuthorities(data.authorities);
You have a typo in your condition in the getAuthorities method. The token is undefined. The error you have comes from trying to parse undefined in JSON.parse(...). You check the TOKEN_KEY in storage but read AUTHORITIES_KEY
Your code:
if (sessionStorage.getItem(TOKEN_KEY)) {
JSON.parse(sessionStorage.getItem(AUTHORITIES_KEY)).forEach(authority => {
Correct code:
if (sessionStorage.getItem(AUTHORITIES_KEY)) {
JSON.parse(sessionStorage.getItem(AUTHORITIES_KEY)).forEach(authority => {
I have a web app which is secured with JWT. How to make it remember my login data and not to enter it all again if I open a new tab? I use axios.post to the authenticate endpoint and save the token in localStorage
My code of the authentication service in frontend:
import axios from 'axios'
const API_URL = 'http://localhost:8080/map-runner'
export const USER_NAME_SESSION_ATTRIBUTE_NAME = 'authenticatedUser'
class AuthenticationService {
executeJwtAuthenticationService(username, password) {
return axios.post(`${API_URL}/authenticate`, {
username,
password
})
}
registerSuccessfulLoginForJwt(username, token) {
sessionStorage.setItem(USER_NAME_SESSION_ATTRIBUTE_NAME, username)
localStorage.setItem("token", token)
}
createJWTToken(token) {
return 'Bearer ' + token
}
logout() {
sessionStorage.removeItem(USER_NAME_SESSION_ATTRIBUTE_NAME);
}
isUserLoggedIn() {
let user = sessionStorage.getItem(USER_NAME_SESSION_ATTRIBUTE_NAME)
if (user === null) return false
return true
}
getLoggedInUserName() {
let user = sessionStorage.getItem(USER_NAME_SESSION_ATTRIBUTE_NAME)
if (user === null) return ''
return user
}
setupAxiosInterceptors(token) {
axios.interceptors.request.use(
(config) => {
if (this.isUserLoggedIn()) {
config.headers.authorization = token
}
return config
}
)
}
}
export default new AuthenticationService()
Now my Login Component:
import React, { Component } from 'react'
import AuthenticationService from '../service/AuthenticationService';
class LoginComponent extends Component {
constructor(props) {
super(props)
this.state = {
username: '',
password: '',
hasLoginFailed: false,
showSuccessMessage: false
}
}
handleChange = (event) => {
this.setState(
{
[event.target.name]
: event.target.value
}
)
}
loginClicked = () => {
AuthenticationService
.executeJwtAuthenticationService(this.state.username, this.state.password)
.then((response) => {
AuthenticationService.registerSuccessfulLoginForJwt(this.state.username, response.data.token)
console.log(response.data.token);
this.props.history.push(`/calculations`)
}).catch(() => {
this.setState({ showSuccessMessage: false })
this.setState({ hasLoginFailed: true })
})
}
render() {
return (
<div>
<h1>Вход</h1>
<div className="container">
{this.state.hasLoginFailed && <div className="alert alert-warning">Неверные данные</div>}
{this.state.showSuccessMessage && <div>Вход выполнен успешно</div>}
Имя пользователя: <input type="text" name="username" value={this.state.username} onChange={this.handleChange} />
Пароль: <input type="password" name="password" value={this.state.password} onChange={this.handleChange} />
<button className="btn btn-success" onClick={this.loginClicked}>Вход</button>
</div>
</div>
)
}
}
export default LoginComponent
The backend in spring boot is quite long even regarding the JWT part, so I guess I'll leave the link to the tutorial which was the basis of my backend. The paths are a bit different but in general these backend parts are the same.. I also tried to use sessionstorage instead of localstorage, doesnt work. If possible, maybe we can test everything out firstly replicating the whole tutorial code as the jwt part is almost the same there (I have a copy and they have a link to their github in the article)
You must be having login page where you would be sending jwt token at the time of login so
store the jwt token at the time if login as
axios.post("http:yourAPIaddresshere", formData)
.then((response) => {
if(response.status === 200) {
// storing session
localStorage.setItem('session', response.data.token)
this.props.history.push('home');
} else {
this.showMessage('Error message', "Please check your credentials.")
}
}
});
}
This is where your session is stored in localStorage now in other all the files retrieve the token
In same login file also do :
componentDidMount(){
if (localStorage.getItem('session') !== null) {
this.props.history.push('home')
}
}
this will always push your navigation to other tabs.
To make your other tabs/pages secure also check session if not null it won't let you open other pages using routes without session token
componentDidMount(){
if (localStorage.getItem('session') === null)
this.props.history.push('login') }
P.S: Make sure to empty the sesion token at the time of logout as :
localStorage.removeItem('session');
You can save the token either in local storage or cookie. And every-time you send any xhr request you can pass the token in the header.
In my Angular 4 application the is a service as below which maintains booking object list. This booking list is a Subject.
//imports
#Injectable()
export class BookingTreeService {
selBooking: Booking;
bookingList: Array<Booking> = [];
bkgList$: Observable<Array<Booking>>;
private bkgListSubject: Subject<any>;
constructor( private resHttp: ResHttpService) {
this.bkgListSubject = new Subject<Array<Booking>[]>();
this.bkgList$ = this.bkgListSubject.asObservable();
}
loadBooking(bookingId:number): Observable<any> {
let item = this.bookingList.filter(b => b.bookingId === bookingId);
if (item && item.length > 0) {
return this.retrieveBooking(bookingId);
// here, I don't want to call http call. Need to update the booking tree
}
else {
return this.loadBookingAndLock(bookingId);
}
}
loadBookingAndLock(bookingId: any): Observable<any> {
return this.resHttp.loadBookingAndLock(bookingId)
.map(response => {
//handle response
})
.catch(this.handleError);
}
retrieveBooking(bookingId: any): Observable<any> {
return this.resHttp.retrieveBooking(bookingId)
.map(response => {
//handle response
})
.catch(this.handleError);
}
addBooking(booking: Booking) {
this.bookingList.push(booking);
this.updateBookingTree(booking);
}
updateBookingTree(booking: Booking):void {
this.bookingList.map((b:Booking) => {
b.active = b.bookingId === booking.bookingId;
});
this.bkgListSubject.next(this.bookingList);
}
}
In the component I call the loadBooking inside ngOnInit as below.
loadBooking() {
this.paramsSubscription = this.route.params
.switchMap((params: Params) => this.bkgTreeService.loadBooking(+params['id']))
.subscribe(
response => {
},
(error) => {
console.log(error);
}
);
}
If the selected booking is already includes in the booking tree don't want to call http request again, only want to update the booking tree. But inside the switchMap it accepts only Observable. So that how could it be handled?
Any suggestions are appreciated.
Here what i understood is you want to cache the data, so for that you can use Rxjs Caching using shareReplay.
More details at :- https://blog.thoughtram.io/angular/2018/03/05/advanced-caching-with-rxjs.html
You must store the booking list using "tap" when you make the call
loadBookingAndLock(bookingId: any): Observable<any> {
return this.resHttp.loadBookingAndLock(bookingId)
//When the observable finished
.pipe(tap(response=>{
//we concat the response to the bookingList
if (!this.bookingList.find(b=>b.bookingId==bookingId)
this.bookingList.concat(response);
}))
.catch(this.handleError);
}
I am new to angular2, and we have a basic running application and I need to write a new login page for this application.
I looked at this tutorial and pretty much am able to replicate this same as standalone:
http://4dev.tech/2016/03/login-screen-and-authentication-with-angular2/
but when I looked to integrate with existing application, I see already different home page defined in app.component, should I rename this app.component to a new component and redirect to it from login component.
what would be the best way to integrate this with minimal changes..best practices around this
you have to create a loging component and define the the login in route configuration like this
export const routes:RouterConfig = [
{path: 'login', component: LoginComponent},
{path: '', component: LoginComponent}] //default to login page
in login component. i code like
export class LoginComponent implements OnInit {
private jwtHelper:JwtHelper = new JwtHelper();
messages:String[] = [];
localUser = {
username: '',
password: ''
}
constructor(private _service:LoginService, private _router:Router) {
}
login() {
this._service.login(this.localUser).then((data) => {
if (data) {
this._router.navigate(['/companies']);
}
},
(error) => {
this.messages = error;
});
}
clearfields() {
this.localUser.username = '';
this.localUser.password = '';
this.messages = [];
}
ngOnInit():any {
if (window.localStorage.getItem('auth_key') === undefined) {
console.log("window.localStorage.getItem('auth_key'): " + window.localStorage.getItem('auth_key'));
}
else if (window.localStorage.getItem('auth_key') != null && !this.jwtHelper.isTokenExpired(window.localStorage.getItem('auth_key'))) {
this._router.navigate(['/companies']);
}
}
after login you can navigate to any page abased on your need