Microsoft single sign on - react-aad-msal library - can't get access token - msal

I'm developing a web application with a react frontend and a .NET CORE 3.1 backend and was asked to add Azure AD single sign on capabilities. I'm using the react-aad-msal library (https://www.npmjs.com/package/react-aad-msal). I'm calling MsalAuthProvider.getAccessToken() and get this error:
Can't construct an AccessTokenResponse from a AuthResponse that has a token type of "id_token".
Can anyone help me?
Anyone? Btw. getAccessToken() is actually inside the standard msal library, if that helps.

I found a solution myself by going into packages.json and lowering the version number on "msal" in "dependencies" like this:
"msal": "~1.3.0",

Change the scopes in authProvider.
export const authProvider = new MsalAuthProvider(
{
auth: {
authority: 'https://login.microsoftonline.com/5555555-5555-5555-5555-555555555555',
clientId: 'AAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA',
postLogoutRedirectUri: 'http://localhost:3000/signin',
redirectUri: 'http://localhost:3000/signin',
validateAuthority: true,
navigateToLoginRequestUrl: false
},
system: {
logger: new Logger(
(logLevel, message, containsPii) => {
console.log("[MSAL]", message);
},
{
level: LogLevel.Verbose,
piiLoggingEnabled: false
}
)
},
cache: {
cacheLocation: "sessionStorage",
storeAuthStateInCookie: true
}
},
{
scopes: ["openid", "profile", "user.read"] // <<<-----------|
},
{
loginType: LoginType.Popup,
tokenRefreshUri: window.location.origin + "/auth.html"
}
);

Related

ERR_TOO_MANY_REDIRECTS on vercel after deploying Nextjs App

I deployed my nextjs app to Vercel and it was a success.
I can see a preview of the website and even the log saying it works well.
But i try to access the website via the default Vercel domain :
https://tly-nextjs.vercel.app/
I get an ERR_TOO_MANY_REDIRECTS.
I do not have this problem locally.
I tried :
Disabling a language redirect that I use (/en for english folks, and / for french people).
Disabling the language detector of i18next.
But none of these solutions changed anything.
Any ideas ?
i18n.js file
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import Cache from 'i18next-localstorage-cache';
import LanguageDetector from 'i18next-browser-languagedetector';
const fallbackLng = ['fr'];
const availableLanguages = ['fr', 'en'];
const en = require('./locales/en/common.json');
const fr = require('./locales/fr/common.json');
const options = {
order: ['querystring', 'navigator'],
lookupQuerystring: 'lng'
}
const cacheOptions = {
// turn on or off
enabled: true,
// prefix for stored languages
prefix: 'i18next_res_',
// expiration
expirationTime: 365*24*60*60*1000,
// language versions
//versions: {}
}
i18n
.use(Cache)
.use(initReactI18next)
.use(LanguageDetector)
.init({
cache: cacheOptions,
fallbackLng: fallbackLng,
debug: true,
detection: options,
supportedLngs: availableLanguages,
nonExplicitSupportedLngs: true,
resources: {
en: {translation: en},
fr: {translation: fr},
},
interpolation: {
escapeValue: false,
},
react: {
wait: true,
useSuspense: true,
},
});
export default i18n;
My change Language function :
const changeLanguageInHouse = (lang, bool) => {
setLoading(true);
i18next.changeLanguage(lang).then((t) => {
setLanguage(lang);
bake_cookie("langChoice", lang);
setLoading(false);
if (bool === true) {
var newUrl2 = (lang === "fr" ? "" : "/en") + asPath;
window.location.replace(newUrl2);
}
});
};
What happend at your server is following:
You enter https://tly-nextjs.vercel.app/ and it is redirected to /en with HTTP-Status-Code 307 (Temporary Redirect).
And /en redirect with 301 (Permanent Redirect) to /.
You can reproduce this by open the Browser-Dev-Tools and have a look at the Network Tab.
It might be, that you have some kind of url-rewriting activated at your server, which redirect everything to your domain-root.
Is there a public repo available for this? Here is how it worked for me.
Try changing the order of the locales and the default locale (not sure this helps, but it changed something for me. Undocumented if that is the case!)
So I put the default locale first (which is nl for me) in both the locales array and the domains array.
Let me know if that helps!
module.exports = {
i18n: {
localeDetection: false,
// These are all the locales you want to support in
// your application
locales: ['nl', 'en'],
// This is the default locale you want to be used when visiting
// a non-locale prefixed path e.g. `/hello`
defaultLocale: 'nl',
// This is a list of locale domains and the default locale they
// should handle (these are only required when setting up domain routing)
domains: [
{
domain: 'example.be',
defaultLocale: 'nl',
},
{
domain: 'example.com',
defaultLocale: 'en',
},
],
},
trailingSlash: true,
};
I changed all my getInitialProps to getServerSideProps
and realised I was doing a redirect on response :
res.writeHead(301, { Location: "/" })
I just delete it.
And now I don't have this endless redirect.
Doing this worked for me...
https://ardasevinc.tech/cloudflare-vercel-too-many-redirects
I think it's the actual solution to the cause of the problem rather than a bandage!

Azure active directory integration angular + adal+ spring boot

I'm trying to integrate Azure active directory with an application I have. The application front end is Angular 7 and back end is Spring boot. What I did was creating a web app in Azure portal and in Angular side by using microsoft adal library get the access token then passing that token with every request and authenticate that token in the spring boot backend. What I need to know is the way I'm doing is correct ie, I'm using the same azure app credentials(Client id, Tenant id.....) in Angular and spring boot. Is we need to create different app for fronend and backend. And getting access token from front end is correct or not.
app.module.ts
-----------------
function initializer(adalService: MsAdalAngular6Service) {
return () => new Promise((resolve, reject) => {
if (adalService.isAuthenticated) {
resolve();
} else {
adalService.login();
}
});
}
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule,
MsAdalAngular6Module.forRoot({
tenant: 'xxxbef18-40f6-44e6-972c-407462a99xxx',
clientId: 'xxx4602f-e3c8-4114-ae23-42bf9e57dxxx',
redirectUri: 'http://localhost:4200',
navigateToLoginRequestUrl: false,
cacheLocation: 'localStorage'
})
],
providers: [ {
provide: APP_INITIALIZER,
useFactory: initializer,
multi: true,
deps: [MsAdalAngular6Service]
},
{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptorService,
multi: true
}],
bootstrap: [AppComponent]
})
export class AppModule { }
Filter class in backend
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AADAuthenticationFilter aadAuthFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
//allow all request access this url
http.authorizeRequests().antMatchers("/home").permitAll();
//access to this url requires authentication
http.authorizeRequests().antMatchers("/api/**").authenticated();
http.authorizeRequests().anyRequest().permitAll();
http.addFilterBefore(aadAuthFilter, UsernamePasswordAuthenticationFilter.class);
}
}
application.properties
# Specifies your Active Directory ID:
azure.activedirectory.tenant-id=92cbef18-40f6-44e6-972c-407462a99xxx
# Specifies your App Registration's Application ID:
spring.security.oauth2.client.registration.azure.client-id=xxx42c78-c557-48ef-8f09-be40c2093xxx
azure.activedirectory.client-id=xxx4602f-e3c8-4114-ae23-42bf9e57dxxx
# Specifies your App Registration's secret key:
spring.security.oauth2.client.registration.azure.client-secret=xxx-~H98Y68m5fFw9_P9sy-c4C4E3lAxxx
azure.activedirectory.client-secret=xxx-~H98Yxxxx5fFw9_P9sy-c4C4E3lAxxx
# Specifies the list of Active Directory groups to use for authorization:
azure.activedirectory.active-directory-groups=users
Any help would be appreciable
In theory, the access token can be obtained from the front end. From your configuration, the back end is equivalent to a resource, which is not a problem in itself, but it is generally not recommended.
As you can imagine, our general approach is to create different applications for the front end and the back end, using the front end as the web app end and the back end as the web server end, which provides access tokens.

Store data to db using Nativescript-vue

I'm starting to learn Vue JS and now trying to learn in nativescript-vue.
What should I do in order to have an offline DB where I can store my data without using internet connection. I heard about Firebase but I think I can't use my app if I don't have an internet connection. Thanks!
You can use Firebase with persistence enabled or you can use sqlite (https://www.npmjs.com/package/nativescript-sqlite) with vuex quite nicely.
Simple solution:
If you use applications settings within your app you can store simple data in a json object.
If you check out: https://www.nativescript.org/blog/key-value-local-storage-in-a-vue.js-nativescript-app-with-vuex
This article includes a step by step example of how to implement including using vuex store.
from that page: (store)
import Vue from 'nativescript-vue';
import Vuex from 'vuex';
import * as ApplicationSettings from "application-settings";
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
firstname: "",
lastname: ""
},
mutations: {
load(state) {
if(ApplicationSettings.getString("store")) {
this.replaceState(
Object.assign(state, JSON.parse(ApplicationSettings.getString("store")))
);
}
},
save(state, data) {
state.firstname = data.firstname;
state.lastname = data.lastname;
}
}
});
Vue.prototype.$store = store;
module.exports = store;
Then save in your app with:
methods: {
save() {
this.$store.commit("save", this.input);
},
}
You will need to add a mutation to save to application settings as well:
a simple way to do that is add to the save mutation:
save(state, data) {
state.firstname = data.firstname;
state.lastname = data.lastname;
ApplicationSettings.setString("store", JSON.stringify(state));
}

Cognito admin_initiate_auth responds with exception User does not exist when creating a new user

I'm trying to create a new user in a Cognito user pool from my ruby backend server. Using this code:
client = Aws::CognitoIdentityProvider::Client.new
response = client.admin_initiate_auth({
auth_flow: 'ADMIN_NO_SRP_AUTH',
auth_parameters: {
'USERNAME': #user.email,
'PASSWORD': '123456789'
},
client_id: ENV['AWS_COGNITO_CLIENT_ID'],
user_pool_id: ENV['AWS_COGNITO_POOL_ID']
})
The response I get is Aws::CognitoIdentityProvider::Errors::UserNotFoundException: User does not exist.
I'm trying to follow the Server Authentication Flow (https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html), and from that I understood that I could create a new user using admin_initiate_auth.
Am I doing something wrong here?
Thanks
You're using the wrong method. admin_initiate_auth is for logging in/authenticating a user with the ADMIN_NO_SRP_AUTH turned on.
You need to use the sign_up method:
resp = client.sign_up({
client_id: "ClientIdType", # required
secret_hash: "SecretHashType",
username: "UsernameType", # required
password: "PasswordType", # required
user_attributes: [
{
name: "AttributeNameType", # required
value: "AttributeValueType",
},
],
validation_data: [
{
name: "AttributeNameType", # required
value: "AttributeValueType",
},
],
analytics_metadata: {
analytics_endpoint_id: "StringType",
},
user_context_data: {
encoded_data: "StringType",
},
})
You can find it in the AWS Cognito IDP docs here.

Configurable redirect URL in DocPad

I'm using DocPad to generate system documentation. I am including release notes in the format
http://example.com/releases/1.0
http://example.com/releases/1.1
http://example.com/releases/1.2
http://example.com/releases/1.3
I want to include a link which will redirect to the most recent release.
http://example.com/releases/latest
My question: how do I make a link that will redirect to a relative URL based on configuration? I want this to be easily changeable by a non-programmer.
Update: I've added cleanurls into my docpad.js, similar to example below. (see code below). But using "grunt docpad:generate" seems to skip making the redirect (is this an HTML page?). I've a static site. I also confirmed I'm using the latest cleanurls (2.8.1) in my package.json.
Here's my docpad.js
'use strict';
var releases = require('./releases.json'); // list them as a list, backwards: ["1.3", "1.2", "1.1", "1.0"]
var latestRelease = releases.slice(1,2)[0];
module.exports = {
outPath: 'epicenter/docs/',
templateData: {
site: {
swiftype: {
apiKey: 'XXXX',
resultsUrl: '/epicenter/docs/search.html'
},
ga: 'XXXX'
},
},
collections: {
public: function () {
return this.getCollection('documents').findAll({
relativeOutDirPath: /public.*/, isPage: true
});
}
},
plugins: {
cleanurls: {
simpleRedirects: {'/public/releases/latest': '/public/releases/' + latestRelease}
},
lunr: {
resultsTemplate: 'src/partials/teaser.html.eco',
indexes: {
myIndex: {
collection: 'public',
indexFields: [{
name: 'title',
boost: 10
}, {
name: 'body',
boost: 1
}]
}
}
}
}
};
When I run grunt docpad:generate, my pages get generated, but there is an error near the end:
/data/jenkins/workspace/stage-epicenter-docs/docs/docpad/node_modules/docpad-plugin-cleanurls/node_modules/taskgroup/node_modules/ambi/es6/lib/ambi.js:5
export default function ambi (method, ...args) {
^^^^^^
I can't tell if that's the issue preventing this from running but it seems suspicious.
Providing that your configuration is available to the DocPad Configuration File, you can use the redirect abilities of the cleanurls plugin to accomplish this for both dynamic and static environments.
With a docpad.coffee configuration file, it would look something like this:
releases = require('./releases.json') # ['1.0', '1.1', '1.2', '1.3']
latestRelease = releases.slice(-1)[0]
docpadConfig =
plugins:
cleanurls:
simpleRedirects:
'/releases/latest': '/releases/' + latestRelease
module.exports = docpadConfig

Resources