Wrong audience for JWT using ADAL.js - javascript

I'm using the adal-angular library (but not with Angular) in my SPA to try to acquire an access token that I can use to call the SharePoint APIs (https://<my-tenant>.sharepoint.com/_api/).
I've registered an application in Azure AD and enabled the implicit flow in the manifest, and I'm now running my SPA locally, which is why there's a localhost redirect URI. The code below is being executed on startup:
const context = new AuthenticationContext({
clientId: '<my-client-id>',
redirectUri: 'http://localhost:3000/signin',
popUp: true,
loginResource: 'https://<my-tenant>.sharepoint.com',
callback: () => window.location.reload()
});
const user = context.getCachedUser();
if (!user) {
context.login();
} else {
context.acquireToken('https://<my-tenant>.sharepoint.com', (error, token) => {
console.log(error, token);
});
}
I'm already logged into the SharePoint site, so with this config everything happens automatically and I see a JWT access token logged to the console. However, when I inspect the token, I see that the audience is <my-client-id>. When making a call to https://<my-tenant>.sharepoint.com/_api/v1.0/me using the access token, I then get a 401 response with the following error message:
{"error_description": "Exception of type 'Microsoft.IdentityModel.Tokens.AudienceUriValidationFailedException' was thrown."}
I'm pretty sure this all boils down to me not understanding the OAuth2 flow properly, but... how can I acquire a token that SharePoint can actually be used with SharePoint? Am I thinking about this the wrong way? It kinda defeats the purpose if the token retrieved by my app can only be used to authenticate against my own app.

Getting an access token to SharePoint is well described here:
OneDrive for Business authentication and sign in
You should consider first getting a token to the Discovery Endpoint:
Using an access token received for resource
https://api.office.com/discovery/ you can make a request to the
discovery API to learn which services are available
If the call is successful, the response body contains JSON data with
information about the services available for the user and your app.
{
"#odata.context": "https:\/\/api.office.com\/discovery\/v1.0\/me\/$metadata#allServices",
"value": [
{
"#odata.type": "#Microsoft.DiscoveryServices.ServiceInfo",
"capability": "MyFiles",
"serviceApiVersion": "v2.0",
"serviceEndpointUri": "https:\/\/contoso-my.sharepoint.com\/_api\/v2.0",
"serviceResourceId": "https:\/\/contoso-my.sharepoint.com\/"
}
]
}
There you should get your valid Resource ID... but the issue here may just be that you did not include a forwardslash (/) at the end of the Resource URL in your sample code.

Related

can we authenticate with response type as access token in MSAL JS

In Our application uses AAD for authenticating the corporate users within our organization only.
Is that possible to set the response type as access token instead of default id_token ? Here is my config.
// const msalConfig = {
// auth: {
// clientId: configuration.msal.clientId,
// tenantId:configuration.msal.tenantId,
// redirectUri: window.location.href
// },
// cache: {
// cacheLocation: 'sessionStorage',
// storeAuthStateInCookie: true
// }
// };
I get the error as but if i enable id_token in authentication under Azure App registrations authentication it works again.. but is that possible to get the authentication done just with access token enabled.
msal handleRedirectCallback ServerError: AADSTS700054: response_type 'id_token' is not enabled for
the application.
T
MSAL.JS is used implement browser level flows like
implicit flow.
Id token is required for implicit flow to validate that a user is
who they claim to be and get additional useful information about
Then for security purpose.
In implicit flow we need to first authorize with id token and then only we can request for access token.
Implicit flow is recommended only if the application has a single-page architecture (SPA), has no back-end components.
You are facing the error because implicit flow is not enabled.
To enable implicit flow please check Access tokens and ID tokens in your registered application as mentioned below
Do you mean you want to use Authorization Code Flow ? If so, you have to use MSAL v2.
EDIT: sorry, I misread the question.
You cannot directly ask for an access token with MSAL, you have to login first (id_token) and then acquire a token (access_token).
This is all explained in the docs.

Use Google Service Account with google API JavaScript Client

I wanted to know if it was possible possible to use a service account to request data from any google API but using this library: https://github.com/google/google-api-javascript-client
I managed to find out how to use the library with OAuth2.0 credential from google cloud console.
But my real need requires me to use a service account to fetch these data.
Here's the code I used to fetch data from OAuth2.0 credentials:
initClient() {
return gapi.client.init({
apiKey: this.GSC_API_KEY, // already defined in the application
client_id:
"xxxxxxxxxxxxxxxxx.apps.googleusercontent.com",
scope:
"https://www.googleapis.com/auth/webmasters https://www.googleapis.com/auth/webmasters.readonly",
discoveryDocs: [
"https://www.googleapis.com/discovery/v1/apis/webmasters/v3/rest"
]
});
},
gapiList() {
this.initClient()
.then(() => {
// Executes an API request, and returns a Promise.
// The method name `webmasters.sites.list` comes from the API webmasters.
return gapi.client.webmasters.sites.list();
})
.then(
response => {
console.log(response.body);
},
err => {
console.error(err.details);
}
);
},
Here's the code that request the API:
gapi.load("client", this.gapiList);
It does return me good data.
But my final purpose requires me to use a service account.
The initClient function does need a client_id to load correctly. If I'm giving the client_id of the service account it does return me an error.
"Not a valid origin for the client: http://localhost:8080/ has not been whitelisted for client ID xxxxxxxxxxxxx. Please go to https://console.developers.google.com/ and whitelist this origin for your project's client ID.
The error message is telling me to whitelist the localhost (where I am currently working) but I don't find how to whitelist localhost for a service account.
Hope I gave enough informations.
Thank for any reply and help.
As the message tells, you need to allow localhost:8080 as an origin to call the API. To protect you and your users, Google restricts your OAuth 2.0 application to using Authorized Domains. If you have verified the domain with Google, you can use any Top Private Domain as an Authorized Domain.
After you add an Authorized Domain, you can use any of its subdomains or pages, and any other associated country codes. Add your Authorized Domains before you add your redirect or origin URIs, your homepage URL, your terms of service URL, or your privacy policy URL.
To accomplish this, follow these steps:
In the GCP Console, click APIs & Services and then OAuth consent screen. You might have to click Menu Menu first.
In the Application name field, enter G Suite Migrate and click Save.
In the left menu, click Credentials.
Click Create credentials and then OAuth client ID.
Select Web application.
In the Name field, enter a name for the OAuth web client.
In the Authorized JavaScript origins field, enter the URL that you’ll use to access the G Suite Migrate platform (for example,
http://localhost:5131).
Click Create.
Make a note of the client ID shown in the Client ID field. You’ll need it when you set up the G Suite Migrate platform. Tip: You can
also access the client ID from APIs & Serviceand thenCredentials.
Click OK.
Note: It might take some time for the authorization process to
complete.
Extra: If you want a service account to be able to call an API on a users behalf, you will also need to delegate domain-wide authority to the service account. This is explained in detail here.
You can not use service account with Google JavaScript client library.
You should use to Oauth2 authentication. If you have to use service account you need to use server sided language such like node.js or python etc.

Graph Security endpoint throwing an HTTP 403 with ADALJS

Trying to build a client-side app using the Microsoft Graph Security API.
We've made the grants in the Azure Portal, granted Admin Consent, and the JWT is showing the scopes are present (snippet below):
"scp": "Calendars.Read MailboxSettings.Read offline_access People.Read profile SecurityEvents.Read.All SecurityEvents.ReadWrite.All User.Read User.Read.All",
Here's how we're requesting the token:
// acquire token for ms graph. the service we're acquiring a token for
// should be the same service we call in the ajax request below
authContext.acquireToken('https://graph.microsoft.com', (error, token) => {
// Handle ADAL Error
if (error || !token) {
printErrorMessage('ADAL Error Occurred: ' + error);
return;
}
this.token = token; //update our data with the token
});
But when we hit the endpoint with a web call, we're still getting a 403 with no data returned:
$.ajax({
type: "GET",
url: "https://graph.microsoft.com/v1.0/security/alerts",
headers: {
'Authorization': 'Bearer ' + this.token,
}
}).done(async (data) => {
console.log(data);
}).fail(() => {
console.log('Error getting top 10 people!');
});
And here's the underlying error (via Postman):
{
"error": {
"code": "UnknownError",
"message": "Auth token does not contain valid permissions or user does not have valid roles.",
"innerError": {
"request-id": "6411dbc9-eebb-4522-b789-62ab5f754d0c",
"date": "2019-04-23T15:17:12"
}
}
}
Edit: The user accessing the app has the "Security reader" Directory role attached.
Any assistance would be GREATLY appreciated. :)
It looks like your app has the correct scopes, but the user that is requesting alerts from the Microsoft Graph Security API does not have a Security reader role in Azure AD.
To add roles to users, sign in to Azure portal as the tenant admin then select the Azure Active Directory blade > Users > select the name of the user > Directory Role > and then select Add role.
Once the user has access to read security information, they should be able to receive alerts through the Microsoft Graph Security API.
Source: https://learn.microsoft.com/graph/security-authorization#assign-azure-ad-roles-to-users
I’ve been working behind-the-scenes with some MS DEV resources, and we believe we’ve tracked down why this doesn’t work.
Taken from an email:
The implicit grant in through AAD uses response_mode=fragment by default. Once the response mode is changed to response_mode=form_post the id token ,and access token if requested, are sent as a POST request and contain the wids claim which allows the Graph API security endpoints to be used.
The workaround proposed there was to basically build a server-side app that would catch the POST request that would have the roles, then use that to call the Graph Security API.
This works, but basically means implicit flow client side apps are essentially incompatible with the Graph Secuirty API. Super frustrating and extremely difficult to track down from the documentation.
Hopefully there is some other mechanism MS can come up with.

Get all user photos from instagram

I'm working on some test app, that uses auth0 and IONIC. I have established connection with auth0, and now i want to get user data by this code:
$http({
method: 'GET',
url: 'https://api.instagram.com/v1/users/self/?access_token='+store.get('accessToken')
}).then(function successCallback(response) {
console.log(response);
}, function errorCallback(response) {
console.log(response);
});
I get 400 Access-Control-Allow-Origin error. Can anybody tell me what to do? I can't find anythink on internet that'll help me...
Disclosure: I work for Auth0
The AccessToken returned at the end of Auth0 Login flow is an access token valid for calling Auth0's API's and not Instagrams. In order to do this you will need the Identity Provider's access token in this case that is Instagram.
The complete flow will look like the following
User Logs in from Instagram
Your IONIC app makes a call to your server
Your server fetches the IdP Access Tokens from Auth0 using either a non-interactive client flow or using management api v2
Your server makes the call to Instagram
You can do this via a webtask the following example highlights the flow to fetch the IdP Access Token via Management API v2 https://github.com/vikasjayaram/ext-idp-api-webtask
I am suggesting the flow because Starting Aug 16 2016 these tokens will not be sent back in profile.identities array the as they are so far.

Google Javascript API: What happen after access token expire?

I have a client-side web app (no backend) that uses Google Javascript API.
I have an issue regarding the access-token that I got after the login is successful.
From the callback, we can see that the access-token is set to expire in 1 hour.
expires_in: "3600"
Question is, how can I "get a new token"?
From the documentation, I'm under the impression that after the token is invalid, we have to (and I quote) perform a new re-authorization flow with immediate set to true to get an up-to-date access token.
Source:
https://developers.google.com/+/web/api/javascript
However, when I tried to call again the auth method:
gapi.auth.authorize(parameters, callback)
I got the token object, but there's no access-token inside.
{
client_id: "{my_client_id}.apps.googleusercontent.com"
cookie_policy: undefined
expires_at: "1370371466"
expires_in: "86400"
g_user_cookie_policy: undefined
issued_at: "1370285066"
response_type: "token"
scope: "https://www.googleapis.com/auth/plus.login https://gdata.youtube.com"
}
Am I missing something? How do we usually get a refreshed token after one expired?
On client side, access token is temporary. This is by default online access to user resources. In order to get access tokens again, you need to redirect user for permissions again.
In the OAuth protocol, your app requests authorization to access resources which are identified by scopes, and assuming the user is authenticated and approves, your app receives short-lived access tokens which let it access those resources, and (optionally or more precisely on server side) refresh tokens to allow long-term access.
for server side apps and for offline access of user resource you need to have refresh token Refer to: Google Analytics API Automated Login
Also read: https://developers.google.com/accounts/docs/OAuth2WebServer
https://developers.google.com/accounts/docs/OAuth2UserAgent

Categories