Angular 9 throw CORS error on loading page - oauth-2.0

I am working on Angular 9 application with .NET CORE Web API 3.1 application. I configure Angular client App to authenticate using Auth 2.0 Azure B2C and using angular-oauth2-oidc library in Angular. I am getting CORS Policy error soon I call http://localhost:4200
I can successfully call AD B2C via Postman and get token
When click on Login button, I get following error
{"error":"invalid_request","error_description":"AADB2C90083: The request is missing required parameter: grant_type.\r\nCorrelation ID: xxxxxf7b-f507-48bc-884f-41xxxxxxxxxx\r\nTimestamp: 2020-05-08 09:21:41Z\r\n"}
component
import { Component } from '#angular/core';
import { OAuthService } from 'angular-oauth2-oidc';
import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
import { authConfig } from './auth.config';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Angular9B2CAuthApp';
constructor(private oauthService:OAuthService){
this.configureSingleSignOn();
}
configureSingleSignOn(){
this.oauthService.configure(authConfig);
this.oauthService.tokenValidationHandler = new JwksValidationHandler();
this.oauthService.loadDiscoveryDocumentAndTryLogin();
}
login(){
this.oauthService.initImplicitFlow();
}
logout(){
this.oauthService.logOut();
}
}
Auth.config
error after updating login url

You're setting the token endpoint (which does not support CORS and is not intented for SPA/Implicit Flow/GET calls thus the 400 status code) into your config loginUrl property. You have to set it to your user flow or policy authorize endpoint like this:
{
"loginUrl":"https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/oauth2/v2.0/authorize"
}

Related

Next.js with SSR: How to access cookies to retrieve a JWT and then make a post request with it

Explanation of my problem
So I am currently on a project of my traineeship that requires me to make a small app using Redux to manage the state of the app itself and TanStack Query (a.k.a. React Query v4) to manage asynchronous data from API calls
I am currently using Next.js with Server-Side Rendering (SSR)
And I have a big issue at the moment with one of the pages
So when the user logs in, they're redirected to their profile page, and I want to make a post request with the JSON Web Token stored in cookies to retrieve their info such as their first name and last name
What I did
I used the Next.js function getServerSideProps to make a POST request with the JWT, but because my app uses SSR. I do not have access to cookies and the JWT is stored inside cookies, but I cannot have access to client-side information until the component is fully mounted, also the app crashes when reloading because of that
I used the native React hook useEffect, I declared the variable with the value of the JWT since now I have access to the cookies, but now I cannot use the TanStack Query hook useMutation because you cannot use hooks inside other hooks
(Current implementation) I used a similar approach, but this time declared the JWT variable as undefined along with the constant using the useMutation outside the useEffect and added the JWT variable inside the array of dependencies of the hook, then I retrieved changed the value of the variable to contain the JWT and made a POST request but the post request fails
Here's the code of my current implementation
//React
import { useEffect, useState } from "react";
//Next
import Head from "next/head";
import { NextRouter, useRouter } from "next/router";
//Components
import AccountCard from "#/components/AccountCard/AccountCard";
import Button from "../../components/Button/Button";
//Utils
import { log } from "../../utils/functions/helper-functions";
import { savingsData } from "../../utils/variables/savings-data";
import CookieService from "#/utils/services/cookies.service";
import ApiService from "#/utils/services/api.service";
//Redux
//React-Redux
import { useSelector } from "react-redux";
import { useMutation } from "#tanstack/react-query";
//This is the page of the user
/**
* User page
*
* Route: `/profile/`
* */
export default function Profile(): JSX.Element {
// log({ jsonWebToken });
//We IMPORT the value of the logging state of the user when logging in
const userIsLoggedIn: boolean = useSelector((state: any) => {
return state.isLoggedIn;
});
//We're going to use the router hook to get the current to redirect the user
//if they're not logged in
const router: NextRouter = useRouter();
[...]
let jsonWebToken: string | undefined = undefined;
//We make the POST request
const apiService: ApiService = new ApiService();
const userProfileMutation = useMutation({
mutationFn: (jwt: string) => {
return apiService.postProfile(jwt);
},
onMutate: () => {},
onSuccess: (data, variables) => {
log("SUCCESS, USER INFOS:", data);
},
onError: () => {
log("FAILED TO RETRIEVE USER INFOS");
},
});
//We cannot use the push() method of the router to redirect the user to the sign-in page
//if the user isn't logged in because of the SSR (push is client side only)
useEffect(() => {
//If the user isn't logged in we redirect them to the sign-in page
const userIsNotLoggedIn: boolean = !userIsLoggedIn;
if (userIsNotLoggedIn) {
router.push("/sign-in/");
}
//We recover the jwt inside the browser"s cookies
const cookieCreator: CookieService = new CookieService();
//We initialise it
jsonWebToken = cookieCreator.getCookieByName("jwt")?.value;
log(jsonWebToken);
//#ts-ignore
userProfileMutation.mutate(jsonWebToken);
}, [jsonWebToken]);
return (
<>...</>
);
}
So I'd be very grateful if somebody was able to help me with this issue

Get JWT token in NextJS API

I created a NextJS application integrated with Amazon Cognito. I have a landing page that is using the Amplify Auth API (not the components). Now I need to call an external API to do CRUD operations. What's the best way to do this in NextJS?
I'm thinking I'll create an API in NextJS that will forward the request to the actual external REST API. But my problem is I'm not able to get the JWT Token on the API, since it's a backend code.
A code like this:
Auth.currentSession().then(data => console.log(data.accessToken.jwtToken));
Obviously won't work:
[DEBUG] 20:42.706 AuthClass - Getting current session
[DEBUG] 20:42.706 AuthClass - Failed to get user from user pool
[DEBUG] 20:42.707 AuthClass - Failed to get the current user No current user
(node:20724) UnhandledPromiseRejectionWarning: No current user
How can I get the token in the API?
I have resolved this problem by using the aws-cognito-next library.
Following the documentation from https://www.npmjs.com/package/aws-cognito-next, I have created an auth utility:
import { createGetServerSideAuth, createUseAuth } from "aws-cognito-next";
import pems from "../../pems.json"
// create functions by passing pems
export const getServerSideAuth = createGetServerSideAuth({ pems });
export const useAuth = createUseAuth({ pems });
// reexport functions from aws-cognito-next
export * from "aws-cognito-next";
The pem file was generated by issuing the command (needless to say, you must configure an Amazon Cognito service first):
yarn prepare-pems --region <region> --userPoolId <userPoolId>
And finally, in the NextJs API:
import {getServerSideAuth} from "../../src/utils/AuthUtils"
export default async (req, res) => {
const initialAuth = getServerSideAuth(req)
console.log("initialAuth ", initialAuth)
if (initialAuth) {
res.status(200).json({status: 'success'})
} else {
res.status(400).json({status: 'fail'})
}
}
A simple method is to enable ssrContext in your app and Amplify will provide the user credentials to your api
on the frontend eg _app.tsx (or app.js)
import Amplify, { Auth, API } from "aws-amplify";
import awsconfig from "../src/aws-exports";
Amplify.configure({...awsconfig, ssr: true});
Then in the api you can simply get the currently authenticated cognito user
eg api/myfunction.tsx (or js)
import Amplify, { withSSRContext } from "aws-amplify";
import awsExports from "../../src/aws-exports";
Amplify.configure({ ...awsExports, ssr: true });
/* #returns <CognitoUser>,OR null if not authenticated */
const fetchAuthenticatedUser: any = async (req: NextApiRequest) => {
const { Auth } = withSSRContext({ req });
try {
let user = await Auth.currentAuthenticatedUser();
return user;
} catch (err) {
return null;
}
}

using headers in HTTP client

I am trying to develop a dashboard in angular 7. I wanted to access an URL and get the JSON response in my dashboard. the problem is that my code works fine with an open source URL. but there are few end points, which have authorization request. Aim is to add the headers like the JWT token, authorization to my service and display the data in my dashboard.
I found few resources on the internet which are confusing.
Below is my code I tried in my service.ts
import { Injectable } from '#angular/core';
import {HttpClient} from "#angular/common/http";
#Injectable({
providedIn: 'root'
})
export class DataService {
constructor(private http: HttpClient) { }
getlocations() {
return this.http.get('https://jsonplaceholder.typicode.com/users')
}
}
Any lead on how to add the header and access them would be really helpful.
The simplest way is to modify a specific request by adding HttpHeaders with the authorization parameter. Here's an example:
getlocations() {
return this.http.get(
'https://jsonplaceholder.typicode.com/users',
{ headers: new HttpHeaders({'Authorization': 'Bearer ' + token}) }
);
}

Response with status:0 for URL:null when i am making a rest from ios ionic app

I am making a rest call from ionic app and its working in android device but not in the ios device.
This is how i am making a rest call from my ionic service.
import { Http } from '#angular/http';
import { Injectable } from '#angular/core';
#Injectable()
export class loginService {
constructor(private http : Http){ }
getAllUsers(authData){
console.log(authData);
return this.http.post('http://Some IP add:8080/api/customerr/getUser', authData);
}
}
This is how I am receiving the data in my login.ts file
this.loginservice.getAllUsers(this.loginForm.value).subscribe((response) => {
this.loginResponse = response.json()
} (err)=>{
alert(err)
});
Finally… I solved this problem by changing the API URL call from "http://yourapiurl/" to "https://yourapiurl/" and That sounds good. Please try this one.
I got this from here,
Reference
Thank you.

Untrusted URL error: accessing files from mobile file system in ionic 2

trying to run a video in iframe by setting the url from the mobile local file system on click of the file name, but getting the error of untrusted url even after using the sanitizer function, i am not getting how to deal with this, attached my error screenshot please find it.
also attached my code here, i dont know where i am going wrong. Please help.
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import {DomSanitizer,SafeResourceUrl,} from '#angular/platform-browser';
import { Pipe, PipeTransform } from '#angular/core';
/**
* Generated class for the Nextpage page.
*
* See http://ionicframework.com/docs/components/#navigation for more info
* on Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-nextpage',
templateUrl: 'nextpage.html',
})
export class Nextpage {
iframepath: string;
trustedUrl: SafeResourceUrl;
constructor(public navCtrl: NavController, public navParams: NavParams, public sanitizer:DomSanitizer) {
this.iframepath=navParams.get('path');
this.trustedUrl = sanitizer.bypassSecurityTrustUrl(this.iframepath);
//this.iframepath = 'file:///storage/emulated/0/Android/data/com.ionicframework.ionic2992319/files/dizzy.mp4';
//this.trustedUrl = sanitizer.bypassSecurityTrustUrl(this.iframepath);
console.log("trustedUrl "+this.trustedUrl);
}
goBack(){
this.navCtrl.pop();
}
ionViewDidLoad() {
console.log('ionViewDidLoad Nextpage');
}
}
this is trusted url used in the html file<iframe width="100%" height="300" [src]="trustedUrl"></iframe>

Resources