I am trying to use OAuth2 client of xamarin with facebook, I tried this:
var auth = new OAuth2Authenticator(
clientId: "xxxxxxxxxx",
scope: "",
authorizeUrl: new Uri("https://www.facebook.com/dialog/oauth/"),
redirectUrl: new Uri("http://www.facebook.com/connect/login_success.html"));
auth.Completed += (s, ee) => { .... }
StartActivity(auth.GetUI(this));
However, Completed never called.. Any idea?
After I tested your code and realized that the problem is related to the Facebook App creation, I suggest you to read and follow this.
Related
In the Single Sign-On for Teams
I have the call microsoftTeams.authentication.getAuthToken(authTokenRequest); working; that is, it successfully returns a token resolving to my Azure Active Directory (AAD) successfully. All good. Surprisingly easy. JWT returns with correct audience and scopes (as I have set in my tenant's AAD)
However what I get back when I decode the JWT this seems to just be an Authentication Token, not an Access Token.
Looking at the sample at Task Meow/teams.auth.service.js Does not seem to show how to swap the Auth for the Access Token.
I assume the code will look something like the method getToken() ... but since I have already spent 10+ working days on auth (old ADAL OH MY GOODNESS WAS THIS HORRIBLE) ...
Question:
I was wondering if there are any other good samples of MicrosoftTeams.js Authenticate / Auth Token / MSAL Access token out there?
Anyway, I did solve my problem by the following
Follow TaskMeow example through the abstractions ofauth.service.js > sso.auth.service.js > teams.auth.service.js
As I wanted additional AAD scopes (Files.ReadWrite.All to access the Sharepoint Online files in Teams and Groups.ReadWrite.All - to add Tabs) my getToken() method in teams.auth.service.js is something like the following:
getToken() {
if (!this.getTokenPromise) {
this.getTokenPromise = new Promise((resolve, reject) => {
this.ensureLoginHint().then(() => {
this.authContext.acquireToken(
'https://graph.microsoft.com',
(reason, token, error) => {
if (!error) {
resolve(token);
} else {
reject({ error, reason });
}
}
);
});
});
}
return this.getTokenPromise;
}
Editorial Comment:
Authentication in Microsoft Teams is too difficult
There seems to be many "approaches" in the documentation
The present "SSO" flow still has flaws, and is in "Developer Preview"
If you are an SPA developer it is just too difficult. I am (obviously) not an expert on Authentication -- so current "recipes" are imperative.
This is especially the case if you want more than the default "scopes" as described in Single Sign-on ... and most of the "good stuff" in Microsoft Graph is outside of these default scopes.
Also, this snippet may help.
If you follow the recommended Taskmeow in your Microsoft Teams app, you will get a quick appearance of the Redirect URI (aka /tab/silent-start)
To solve this, adal.js caches the user and access token.
So you can add a check in login()
login() {
if (!this.loginPromise) {
this.loginPromise = new Promise((resolve, reject) => {
this.ensureLoginHint().then(() => {
// Start the login flow
let cachedUser = this.authContext.getCachedUser();
let currentIdToken = this.authContext.getCachedToken(this.applicationConfig.clientId);
if (cachedUser && currentIdToken) {
resolve(this.getUser());
} else {
microsoftTeams.authentication.authenticate({
url: `${window.location.origin}/silent-start.html`,
width: 600,
height: 535,
successCallback: result => {
resolve(this.getUser());
},
failureCallback: reason => {
reject(reason);
}
});
}
});
});
}
return this.loginPromise;
}
I am new to SalesForce and Heroku platform. I am trying to explore and learn as much as possible.
I have developed React app and deployed to Heroku. Its working as expected, but I am at a stage where I am suppose to make Rest API call to Salesforce and get data from SalesForce Object.
I tried jsforce, nforce plugins to connect to Salesforce and fetch data. But unable to.
I used Postman to connect to SalesForce, I am able to connect. But I am getting error when I am trying to connect to Salesforce through code stating (400 bad request).
I have enable CORS on my environment (sandbox). Please let me know if I am missing some configuration settings, it will be really helpful.
var org = nforce.createConnection({
clientId:
"3MVG9sLbBxQYwWqvgNjn4MAlHFib10UPpW1IV7IDsN55vY7xaljuzUxvnsVrk",
clientSecret:
"F762DF566D8B29455F54EC8176CBC19C54CBE953517AC",
redirectUri: "https://www.google.com/",
environment: "sandbox",
mode: "single",
autoRefresh: true
});
let creds = {
username: username,
password: password + securityToken
};
org.authenticate(creds, function(err, resp) {
if (!err) {
console.log("Access Token: " + resp.access_token);
oauth = resp;
} else {
console.log(err);
}
});
And below is the error which I am getting:
I'm actually trying to do a simple login with Linkedin and the new API V2 with Xamarin.Auth extension. I do get the token like this
var auth = new OAuth2Authenticator(
clientId: *****,
clientSecret: *****,
scope: "r_liteprofile",
authorizeUrl: new Uri("https://www.linkedin.com/oauth/v2/authorization"),
redirectUrl: new Uri(*****),
accessTokenUrl: new Uri("https://www.linkedin.com/oauth/v2/accessToken")
);
but when I try to make a request it fails with an {"serviceErrorCode":100,"message":"Unpermitted fields present in PARAMETER: Data Processing Exception while processing fields [/access_token, /format]","status":403}. Code for these error:
var request = new OAuth2Request(
"GET",
new System.Uri("https://api.linkedin.com/v2/me?"
+ "format=json"
+ "&oauth2_access_token="
+ e.Account.Properties["access_token"]),
null,
e.Account
);
var linkedinResponse = await request.GetResponseAsync();
var json = linkedinResponse.GetResponseText();
Console.WriteLine(json);
If I take out the fields, it fails because of empty access token: {"serviceErrorCode":65604,"message":"Empty oauth2 access token","status":401} Code for these error:
var request = new OAuth2Request(
"GET",
new System.Uri("https://api.linkedin.com/v2/me"),
null,
e.Account
);
var linkedinResponse = await request.GetResponseAsync();
var json = linkedinResponse.GetResponseText();
Console.WriteLine(json);
I've confirmed that I've recieved the token. Looking for a solution I found that the token must be in a header but I can't change or add any header. Can anyone help me please?
Thank you very much.
PD: Forgot to say this code is for Android but I needed to do it for iOS aswell.
Hi finally I found the solution to this.
In Linkedin API V2 you have to change your AccessTokenparameterName.
yourOauth2Request.AccessTokenParameterName = "oauth2_access_token";
Hope I can help somebody to not get mad like me.
I am getting invalid signature while using jwt.io to validate my azure ad access token. My id token, however, validates just fine!
I have seen and tried the solutions suggested in
Invalid signature while validating Azure ad access token
and
https://nicksnettravels.builttoroam.com/post/2017/01/24/Verifying-Azure-Active-Directory-JWT-Tokens.aspx
but neither works for my access token.
The access and Id token is generated via Adal.js:
var endpoints = {
"https://graph.windows.net": "https://graph.windows.net"
};
var configOptions = {
tenant: "<ad>.onmicrosoft.com", // Optional by default, it sends common
clientId: "<app ID from azure portal>",
postLogoutRedirectUri: window.location.origin,
endpoints: endpoints,
}
window.authContext = new AuthenticationContext(configOptions);
Why can I validate my ID token, but not my access token?
Please refer to thread : https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/609
but if look at the Jwt.Header you will see a 'nonce'. This means you need special processing. Normal processing will fail.
So if nonce includes in access token , validate signature with JWT.io or JwtSecurityToken won't success .
If anyone else has invalid signature errors, you should check this comment : https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/521#issuecomment-577400515
Solved the issue for my configuration.
Essentially, if you are getting access tokens to access your own resource server and not the Graph API, your scopes parameter should be [CLIENT_ID]/.default (and if you are using the access token to access the Graph API, you don't need to validate the token yourself)
Thanks to Nan Yu I managed to get token that can be validated by any public jwt validator like jwt.io
(couldn't put my comment in the comments section under Nan Yu's answer because its too long).
So as I understand the point from the discussion mentioned by Nan Yu that by default Azure AD generates tokens for Microsoft Graph and these tokens use special signing mechanism so that it is not possible to validate signature using public validators (except jwt.ms Microsoft's validator which most probably knows what mysterious special handling means :) ).
To get access token not for Microsoft Graph that can be validated using public validators I had to:
Remove any Microsoft Graph related scopes (by default I had only one scope configured User.Read so removed it in appConfig > API permissions)
create a custom scope for your application (appConfig > Expose an API > Add scope ...) this scope will look like api://{application-id}/scope-name
add just created scope in the application API permissions (appConfig > API permissions > Add api permission > My APIs > select your application > Delegated Permissions > Check your scope > Add permission)
then use this scope in your openid client scopes, in my case I have: openid offline_access {application-id}/scope-name
Note that in the openid client config newly created scope is used without api:// prefix (offline_access I have to enable refresh_token can be ignored if refresh token mechanism is not used)
Well thanks to #Antoine I fix my code. Here I will let my personal vue.js plugin that is working for everybody else reference:
import { PublicClientApplication } from '#azure/msal-browser'
import { Notify } from 'quasar'
export class MsalService {
_msal = null
_store = null
_loginRequest = null
constructor (appConfig, store) {
this._store = store
this._msal = new PublicClientApplication(
{
auth: {
clientId: appConfig.auth.clientId,
authority: appConfig.auth.authority
},
cache: {
cacheLocation: 'localStorage'
}
})
this._loginRequest = {
scopes: [`${appConfig.auth.clientId}/.default`]
}
}
async handleResponse (response) {
await this._store.dispatch('auth/setResponse', response)
const accounts = this._msal.getAllAccounts()
await this._store.dispatch('auth/setAccounts', accounts)
if (accounts.length > 0) {
this._msal.setActiveAccount(accounts[0])
this._msal.acquireTokenSilent(this._loginRequest).then(async (accessTokenResponse) => {
// Acquire token silent success
// Call API with token
// let accessToken = accessTokenResponse.accessToken;
await this._store.dispatch('auth/setResponse', accessTokenResponse)
}).catch((error) => {
Notify.create({
message: JSON.stringify(error),
color: 'red'
})
// Acquire token silent failure, and send an interactive request
if (error.errorMessage.indexOf('interaction_required') !== -1) {
this._msal.acquireTokenPopup(this._loginRequest).then(async (accessTokenResponse) => {
// Acquire token interactive success
await this._store.dispatch('auth/setResponse', accessTokenResponse)
}).catch((error) => {
// Acquire token interactive failure
Notify.create({
message: JSON.stringify(error),
color: 'red'
})
})
}
})
}
}
async login () {
// this._msal.handleRedirectPromise().then((res) => this.handleResponse(res))
// await this._msal.loginRedirect(this._loginRequest)
await this._msal.loginPopup(this._loginRequest).then((resp) => this.handleResponse(resp))
}
async logout () {
await this._store.dispatch('auth/setAccounts', [])
await this._msal.logout()
}
}
// "async" is optional;
// more info on params: https://quasar.dev/quasar-cli/boot-files
export default ({
app,
store,
Vue
}) => {
const msalInstance = new MsalService(
app.appConfig, store
)
Vue.prototype.$msal = msalInstance
app.msal = msalInstance
}
PD: using quasar framework
If you are using msal.js library with react, add this to your auth configuration.
scopes: [`${clientId}/.default`]
Editing scopes fixed issue for me
I'm creating an web application in Angular2 and i'd like to use Google for the user to login and use the application. Basically, once the user is logged in with Google, he will navigate in the site and make some AJAX call via Angular to the ASP.NET Core Web API.
In my mind, I though that all these calls should contain a JWT (issued by Google) and the ASP.NET Core Web Api would validate the token and then process the request if the token is valid. Simple enough... However, I'm struggling to find out how this could be achieved. All I found is posts talking about how to login via Google in order to use Google APIs. In my case, I don't need any Google API but the login one.
So far, I have this:
export class GoogleAuthenticationService {
private auth: any;
constructor(private userService: UserService) {
}
public bindLoginButton(element: any) {
this.ensureApiIsLoaded().then(() => {
this.auth.attachClickHandler(element, {}, (user) => {
let profile = user.getBasicProfile();
this.userService.set(profile.getName(), profile.getEmail(), user.getAuthResponse().id_token, AuthenticationType.Google);
});
});
}
// TODO: Better type definition of the promise
private ensureApiIsLoaded() {
return new Promise((resolve, reject) => {
gapi.load('auth2', () => {
this.auth = gapi.auth2.init({
client_id: "CLIENT_ID",
cookiepolicy: 'single_host_origin',
scope: 'profile email'
});
resolve();
});
});
}
}
Basically, I'm just initializing "gapi" with my client ID, then I define some properties in the "UserService". This works pretty well. Moreover, I'm using the value returned by user.getAuthResponse().id_token for every call to my web service (I did this following this article). The next step was to try and validate the token in C# (like the sample in Java) but I didn't find any valid resources talking about that and the class used in the Java code does not exists in C#...
Is it that complicated or am I just on the wrong path and this is totally not how the web application is supposed to work. Could someone give me some pointers about this scenario that is, according to me, quite common.