On behalf of flow returns AADSTS50013 Assertion failed signature validation. Reason - The key was not found - azure-active-directory

I have a Web API that needs to make calls to Microsoft Graph API on behalf of the user. I'm using the OBO flow as described here.
To get the access token, I'm posting to
POST - https://login.microsoftonline.com/<my-tenant-id>/oauth2/v2.0/token
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&client_id=<my-client-id>
&client_secret=<my-client-secret>
&assertion=<user's access token>
&scope=https://graph.microsoft.com/files.readwrite.all
&requested_token_use=on_behalf_of
The call fails with the following message:
{
"error": "invalid_grant",
"error_description": "AADSTS50013: Assertion failed signature validation. [Reason - The key was not found.]\r\nTrace ID: fb813f8e-ce15-4d09-bbae-9db5e5195a00\r\nCorrelation ID: ecb4e087-5506-4224-8f11-72fbf574beac\r\nTimestamp: 2020-10-22 02:18:57Z",
"error_codes": [
50013
],
"timestamp": "2020-10-22 02:18:57Z",
"trace_id": "fb813f8e-ce15-4d09-bbae-9db5e5195a00",
"correlation_id": "ecb4e087-5506-4224-8f11-72fbf574beac",
"error_uri": "https://login.microsoftonline.com/error?code=50013"
}
Any ideas what I could be doing wrong?
In response to #Chauncy Zhou,
I have an Angular app with:
"#azure/msal-angular": "^1.0.0",
"msal": "1.3.3"
In app.module, MSAL is configured something like:
MsalModule.forRoot(
{
auth: {
clientId: environment.msClientId, // app1-client-id
authority: environment.msAuthorithy, // https://login.microsoftonline.com/<tenant-id>
redirectUri: environment.msRedirectUri // https://localhost:4200/callback
},
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: false
},
},
{
consentScopes: ['user.read', 'openid'],
protectedResourceMap: [
['https://app-2', ['api://app-2-id/scope-name']],
]
}
)
In a test component:
import { Component, OnInit } from '#angular/core';
import { MsalService } from '#azure/msal-angular';
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {
constructor(private msal: MsalService) {}
ngOnInit(): void {
this.msal.acquireTokenSilent({ scopes: ['api://app-2/scope-name'] }).then(response => {
console.log(response);
});
}
}
Take the access token from console, and do a POST for OBO in postman.

The error is &assertion.
You need to create two application,one is client application(test_1) and the other is web api application(test_2).
In the test_2 application,you need to expose an api.
And in the test_1 application,you need to give test_1 permission to access test_2.
The testing session.
First, use the ROPC grant flow to request access token for test_ 2 application
ropc grant flow
Note that the scope here is api://{test_2 application id}/.default.
Second,use OBO flow to request access token for microsoft graph api endpoint.
on-behalf-of flow

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.

Auth0 with React-Native results in JWT with no data

I have a React-Native application that I am trying to add Auth0 login. So far I have it so it will log in to the app but it is providing a JWT that when I check the jwt.io debugger I get an error message about missing data and the data section is empty. My JWT looks like <string>..<string> when IIRC it should be <string>.<string>.<string> where the middle string that is missing is the data value.
My question is what am I missing that is causing the no data to be in my JWT?
Below is my code with the credentials removed.
// Setup
import Auth0 from 'react-native-auth0'
const auth0 = new Auth0({ domain: '<>', clientId: '<>' })
// Code inside login function
auth0.webAuth
.authorize({
scope: 'openid profile email'
})
.then(credentials => {
// Using this to check the token for the correct format
Alert.alert(credentials.accessToken)
// This is setting it to a global state store where I can access it from elsewhere
globalStorage.set('accessToken', credentials.accessToken)
})
navigation.navigate('list')
Edit**
Here is an example payload/data from a working token I am getting from my Vue.js app
{
"iss": "https://<my domain>.us.auth0.com/",
"sub": "auth0|<user ID>",
"aud": [
"<my audience>",
"https://<my domain>.us.auth0.com/userinfo"
],
"iat": 1661293312,
"exp": 1661379712,
"azp": "<>",
"scope": "openid profile email",
"permissions": [<bunch in here removed for clarity>]
}
Finally figured it out, I needed an audience but it doesn't get added like the package I used with Vue.js but instead gets added to the authorize function. Example code here:
.authorize({
scope: 'openid profile email',
audience: '<>'
})

Login through AAD (Azure Active Directory) in React app doesn't working

I'm trying to implement an authentication through Azure Active Directory for React app.
When I run my application, after login I get a blank page.
In the console I see:
"[HMR] Waiting for update signal from WDS..."
This is my provider:
export const authProvider = new MsalAuthProvider(
{
auth: {
authority: "https://login.microsoftonline.com/common",
clientId: "********-****-****-****-************",
postLogoutRedirectUri: window.location.origin,
redirectUri: window.location.origin,
knownAuthorities: [],
navigateToLoginRequestUrl: true,
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: true,
},
},
{
scopes: [
'user.read',
'api://********-****-****-****-************/Read'
]
},
{
loginType: LoginType.Redirect,
tokenRefreshUri: window.location.origin + '/auth.html'
}
);
package: react-aad-msal
In Azure: I have an app registeration, with SPA platform. Redirect URI: http://localhost:3000.
Anyone has ideas?
I tried many things, and read about it but with no result.
Thanks in advance!
(Moving from comments to answer so that others may more easily find it)
The issue is resolved for the customer by changing the authority URL from Common to specifying single TenantID.

Calling an Azure AD secured Azure Function from React SPA/Azure Static Web App

I'm developing an SPA with React that is hosted as an Azure Static Web App. The App is secured with Azure AD Authentication which works great, I already built a Login that works fine and I can call Azure (Graph) APIs with the token I got and retrieve information for the granted scopes (e.g. user profile picture). To achieve this, I'm using a wrapper called React AAD MSAL which neatly wraps the Microsoft Authentication Library (msal#1.4.0).
So far so good, no problems here. But I'm in need of a backend, of course. I decided to this with Azure Functions, since serverless is the best way for me here. So I made a quick HTTP trigger protoype that runs in Azure as Azure Function und works when I call the URL with the correct paramters.
But of course the Azure Function needs to be secured, so only my React App can call this function. So I thought there should be way to do this through Azure AD, since my user is already logged in as such.
I tried and tried and tried different ways I found online but none of them seem to work or I am doing something wrong.
The general tutorial I tried to follow is this one from MS itself. I tried using the "Express" setting which of course didn't work. I tried the advanced configuration, which also didn't work. The advanced tutorial says you need to have an App registration for the service, I'm not even sure if this is can be my Static Web App or a new on (I tried both with no success). Isn't it enough to tell the Azure Function that it is now AAD secured and may only accept calls from a source secured by an access token that contains the App ID of my app, which is provided in the settings? You can easily provide all these settings, it just doesn't seem to work.
So I'm stalling very early on here. To call the function itself, I first need to get a Authorization Token. According to this tutorial from MS (see "Validate tokens from providers"), I need to send an access token which I got when logging in to my SPA Web App to the Azure Function endpoint ending in .auth/login/aad. Getting this token is easy, since React AAD MSAL provides a method authProvider.getAccessToken() which I can use to extract it. I'm then making a POST request to https://<My Azure Function URI>/.auth/login/aad with the access token in the body as JSON { 'access_token': authToken.accessToken }. I should be getting an Authentication Token which I can then use to call the actual function, but I always get the same response, no matter what I try: You do not have permission to view this directory or page.
So this is where I am. I tried different methods and solutions I found to no avail. Maybe I did something wrong from the ground up, maybe I'm using the wrong methods, I really don't know at this point. Does anyone have experience with this? Is there something wrong in my general approach, do I need to do something else? Or is it just something in the configuration I need to change?
Edit
Since it was asked, here's how I retrieve the token. The concept behind this is using a redux-thunk to dispatch an asynchronous action to the react-redux store. I simplified it not only for this question here but for my testing as well. Right now I'm only trying to get the authentication token and log the answer the POST request is giving me:
import { authProvider } from '../../Authentication/AuthProvider';
//Fetch
async function getAccessToken(authToken) {
const body = { 'access_token': authToken.accessToken };
fetch('https://<My Azure function URL>/.auth/login/aad', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body)
},
).then(response => {
console.log(response);
});
}
export const fetchAddressData = () => async dispatch => {
const token = await authProvider.getAccessToken();
await getAccessToken(token);
// The actual call to the Azure function will go here once we have an Authentication Token
}
The authProvider is a component from react-aad msal and the configuration looks like this:
import { MsalAuthProvider, LoginType } from 'react-aad-msal';
//MSAL Config
const config = {
auth: {
authority: '<Tenant ID>',
clientId: '<Client ID from App registration (Azure Static Web App)>',
redirectUri: window.location.origin
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: true
}
};
// Authentication Parameters
const authenticationParameters = {
scopes: [
'openid',
'user.read',
'https://<Azure Function URI>/user_impersonation'
],
forceRefresh: true
}
// Options
const options = {
loginType: LoginType.Redirect,
tokenRefreshUri: window.location.origin
}
export const authProvider = new MsalAuthProvider(config, authenticationParameters, options)
Edit 2
I tweaked some additional settings trying to work with the user impersonation, still no success. Here's an overview over my current Azure settings that are important for this (did I forget any?).
Azure Function:
Authentication is activated, AAD auth only, advanced settings:
Azure Function - App Registration:
Authentication settings:
Client secret:
Expose an API - Exposing user_impersonation API so the Web App can consume it:
Azure Static Web App (React SPA) - App Registration:
Application URI ID which is used as Token Audience in the Azure Function (advanced authentication setting):
API permissions - using the user_impersonation API which is exposed by the Azure Function App Registration:
Is there anything wrong in this configuration? It mostly likely is, but I don't know what since I followed the tutorial on MSDN. I only added the user_impersonation afterwards since it didn't work.
According to the information provided, you do not configure right scope in your authProvider file. You need to add the scope you define when you create AD application to protect function. So please update the scope as scopes: ["openid","<your function app scope>"] in authProvider.
For example
Create Azure AD application to protect function
Register Azure AD application. After doing that, please copy Application (client) ID and the Directory (tenant) ID
Configure Redirect URI. Select Web and type <app-url>/.auth/login/aad/callback.
Enable Implicit grant flow
Define API scope and copy it
Create client secret.
Enable Azure Active Directory in your App Service app
Create Client AD application to access function
Register application
Enable Implicit grant flow
configure API permissions. Let your client application have permissions to access function
Code
authProvider
import { MsalAuthProvider, LoginType } from "react-aad-msal";
import { Logger, LogLevel } from "msal";
export const authProvider = new MsalAuthProvider(
{
auth: {
authority: "https://login.microsoftonline.com/<tenant>",
clientId: "<>",
postLogoutRedirectUri: window.location.origin,
redirectUri: window.location.origin,
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",
"<the scope you define for your function>",
],
forceRefresh: true,
},
{
loginType: LoginType.Popup,
tokenRefreshUri: window.location.origin + "/auth.html",
}
);
Call API
const CallAPI= async () => {
// You should should use getAccessToken() to fetch a fresh token before making API calls
const authToken = await provider.getAccessToken();
console.log(authToken.accessToken);
let body = { access_token: authToken.accessToken };
let res = await fetch(
"<your function url>/.auth/login/aad",
{
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
}
);
let data = await res.json();
console.log(data);
body = { name: "Azure" };
res = await fetch("<>", {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
"X-ZUMO-AUTH": data["authenticationToken"],
},
body: JSON.stringify(body),
});
data = await res.text();
console.log(data);
};
I was dealing with the same issue for a while. If your sure you are getting the right access token and and passing it correctly, then look into the configuration in the portal. If you automatically created the app registration for the function app, Check how the ISSUER URL is set up. You can find this in the function app>authentication>edit. make sure that the url does not have /v2.0 at the end. Azure function only work with the default(/v1.0) route.

Invalid Credentials error message with google custom search api

I am using google custom search api to search for images in angular.js project.
Here is my Code:
var photosPublic = $resource('https://www.googleapis.com/customsearch/v1',
{ key: '..........ZDtw95C0V98ne4S39SPFi68', cx: '..........75325342:1ttvll7gahc' },
{ searchType:'image' });
return {
search: function(query) {
var q = $q.defer();
photosPublic.get({
q: query
}, function(resp) {
q.resolve(resp);
}, function(err) {
console.log(err);
q.reject(err);
})
return q.promise;
}
}
If i enter url plus all credentials directly in browser it works perfectly fine. But when i include this in my project i receive following response:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "authError",
"message": "Invalid Credentials",
"locationType": "header",
"location": "Authorization"
}
],
"code": 401,
"message": "Invalid Credentials"
}
}
What am i doing wrong?
i had the same issue and wanted to share my solution here because i stumbled here from google search.
the problem appears when you set some default authorization headers in request libraries like $resource or axios etc...
When you provide an Authorization header in the request you're sending to google custom search api the google server is trying to authorize you with this header and isn't even trying to authorize you with the given key and cx.
I don't know much about $resource (maybe someone else could add some code?) but i have a solution for axios:
import axios from 'axios'
export default {
url: 'https://www.googleapis.com/customsearch/v1',
http: axios.create(),
search(text) {
this.http.defaults.headers.common = {};
const key = process.env.GOOGLE_SEARCH_API_KEY
const cx = process.env.GOOGLE_SEARCH_SCOPE_ID
return this.http.get(this.url, {
params: {
q: text,
cx,
key
}
})
}
}
This creates an own axios instance for the search api and resets the headers. Plus: your global axios instance is not affected (perhaps your Auth headers is needed for the communication with your backend).

Resources