How to get user parameters using Amazon Cognito hosted Web UI - javascript

Recently I was using the Sign-up and Sign-in template similar this one developed by Vladimir Budilov.
But now, I've been modifying my application to use the hosted UI developed by Amazon. So my application redirects to the hosted UI, all the authentication is made there and they send me the authentication token, more os less as explained in this tutorial.
Summarizing, I call the hosted UI and do login:
https://my_domain/login?response_type=token&client_id=my_client_id&redirect_uri=https://www.example.com
I'm redirected to:
https://www.example.com/#id_token=123456789tokens123456789&expires_in=3600&token_type=Bearer
So, I have now the token_id but I can't get the current user or user parameters from this. Could anyone help me with informations or some directions?
I've tried the methods in Amazon developer guide .
It works well when I was using Vladimir Budilov's template but trying to use the token_id, I'm not succeeding. Thanks in advance for your time and help.
var data = {
UserPoolId : '...', // Your user pool id here
ClientId : '...' // Your client id here
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(data);
var cognitoUser = userPool.getCurrentUser();
if (cognitoUser != null) {
cognitoUser.getSession(function(err, session) {
if (err) {
alert(err);
return;
}
console.log('session validity: ' + session.isValid());
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId : '...' // your identity pool id here
Logins : {
// Change the key below according to the specific region your user pool is in.
'cognito-idp.<region>.amazonaws.com/<YOUR_USER_POOL_ID>' : session.getIdToken().getJwtToken()
}
});
// Instantiate aws sdk service objects now that the credentials have been updated.
// example: var s3 = new AWS.S3();
});
}

The attributes you configure to be added as claims are already available inside the id_token with base64 encoding (Since its a JWT token).
You can decode the token and access these attributes both at Client Side using Javascript and on Server.
For more info refer the StackOverflow question How to decode JWT tokens in JavaScript.
Note: If you need to trust these attributes for a backend operation, make sure you verify the JWT signature before trusting the attributes.

Here's a specific example of how to parse the callback parameters and set up a user session. This could be initiated in onLoad of your page.
import { CognitoAuth } from 'amazon-cognito-auth-js';
const authData = {
ClientId : '<TODO: add ClientId>', // Your client id here
AppWebDomain : '<TODO: add App Web Domain>',
TokenScopesArray : ['<TODO: add scope array>'], // e.g.['phone', 'email', 'profile','openid', 'aws.cognito.signin.user.admin'],
RedirectUriSignIn : '<TODO: add redirect url when signed in>',
RedirectUriSignOut : '<TODO: add redirect url when signed out>',
IdentityProvider : '<TODO: add identity provider you want to specify>', // e.g. 'Facebook',
UserPoolId : '<TODO: add UserPoolId>', // Your user pool id here
AdvancedSecurityDataCollectionFlag : '<TODO: boolean value indicating whether you want to enable advanced security data collection>', // e.g. true
Storage: '<TODO the storage object>' // OPTIONAL e.g. new CookieStorage(), to use the specified storage provided
};
const auth = new CognitoAuth(authData);
auth.userhandler = {
onSuccess: function(result) {
alert("Sign in success");
showSignedIn(result);
},
onFailure: function(err) {
alert("Error!");
}
};
const curUrl = window.location.href;
auth.parseCognitoWebResponse(curUrl);
Now you're "signed in" as far as the Cognito JS client is concerned, and you can use getCurrentUser(), getSession(), etc. `See "Use case 2" here for more context/details.

Related

Get list of users in a role with SignalR

So what I am trying to accomplish is that when a user sends a message, on the server-side I would like to know which "other" connections are available. I am using SignalR.
From those connections, I would like to know the roles of the users associated with each connection.
I am using ASP.NET Identity, SignalR, and C#.
Then I would like to filter out the connections based on user roles and broadcast a message to only those users.
Any ideas how this can be accomplished.
I think you can use this article to do that
Basically you can send the token from client to server (JWT in this case). JWT can contain all information you need.
The access token function you provide is called before every HTTP
request made by SignalR. If you need to renew the token in order to
keep the connection active (because it may expire during the
connection), do so from within this function and return the updated
token.
So that mean when ever user call signalr they will be authenticate again in the hub.
Or you can add claim to the user so you can detect who request and what role do they have
Sample from the document:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddAuthentication(options =>
{
// Identity made Cookie authentication the default.
// However, we want JWT Bearer Auth to be the default.
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
// Configure JWT Bearer Auth to expect our security key
options.TokenValidationParameters =
new TokenValidationParameters
{
LifetimeValidator = (before, expires, token, param) =>
{
return expires > DateTime.UtcNow;
},
ValidateAudience = false,
ValidateIssuer = false,
ValidateActor = false,
ValidateLifetime = true,
IssuerSigningKey = SecurityKey
};
// We have to hook the OnMessageReceived event in order to
// allow the JWT authentication handler to read the access
// token from the query string when a WebSocket or
// Server-Sent Events request comes in.
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
// If the request is for our hub...
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) &&
(path.StartsWithSegments("/hubs/chat")))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSignalR();
// Change to use Name as the user identifier for SignalR
// WARNING: This requires that the source of your JWT token
// ensures that the Name claim is unique!
// If the Name claim isn't unique, users could receive messages
// intended for a different user!
services.AddSingleton<IUserIdProvider, NameUserIdProvider>();
// Change to use email as the user identifier for SignalR
// services.AddSingleton<IUserIdProvider, EmailBasedUserIdProvider>();
// WARNING: use *either* the NameUserIdProvider *or* the
// EmailBasedUserIdProvider, but do not use both.
}

403 error in calling DerivativeApi of Autodesk Forge

Autodesk Forge's DerivativeApi is not working with my client id and secret. Apis returns unauthorized error, { statusCode: 403, statusMessage: 'Unauthorized’ }.
But they works with the sample's client id/secret (from https://github.com/Autodesk-Forge/forge-api-nodejs-client/blob/master/samples/dmSample.js).
Is there any limitation for calling DerivativeApi (for translating) with free account? or should I do something?
Here is the sample code...
var ForgeSDK = require('forge-apis');
// TODO - insert your CLIENT_ID and CLIENT_SECRET
// Below id/secret from the sample are working, but mine is not.
var CLIENT_ID = 'wmizntnpzCJxPGF9lxsIiTZGbGO2cJqw',
CLIENT_SECRET = 'g5IPJwvhOHcrdbFy';
var derivativesApi = new ForgeSDK.DerivativesApi();
// Initialize the 2-legged oauth2 client
var oAuth2TwoLegged = new ForgeSDK.AuthClientTwoLegged(CLIENT_ID, CLIENT_SECRET,
['data:write', 'data:read', 'bucket:read', 'bucket:update', 'bucket:create'], true);
function defaultHandleError(err) {
console.error('\x1b[31m Error:', err, '\x1b[0m');
}
oAuth2TwoLegged.authenticate().then(function (credentials) {
console.log("**** Got Credentials", credentials);
derivativesApi.getFormats({}, oAuth2TwoLegged, oAuth2TwoLegged.getCredentials()).then(res => {
console.log(res);
}, defaultHandleError);
}, defaultHandleError);
Thanks
First, and extremely important, NEVER share your ID & Secret. If the above is your correct one, please create a new secret (to invalidate this).
Now the ID & Secret should work for any sample, just make sure you activated the APIs for it. On your app, select Model Derivative API on the screen, if not available, please review this article.
Finally, the code sample above is not actually calling Model Derivative. If so, note that files uploaded into one account are not accessible from other accounts, and URNs are unique.

Keycloak JavaScript API to get current logged in user

We plan to use keycloak to secure a bunch of web apps, some written in Java, some in JavaScript (with React).
After the user is logged in by keycloak, each of those web apps needs to retrieve the user that is logged in and the realm/client roles that the user has.
For Java apps, we tried the keycloak Java API (request -> KeycloakSecurityContext -> getIdToken -> getPreferredUsername/getOtherClaims). They seem to work fine
For JavaScript apps, we tried the following code, but could not get Keycloak to init successfully (Note this is in web app code after the user is already authenticated by keycloak, the app is only trying to retrieve who logged in with what roles):
var kc = Keycloak({
url: 'https://135.112.123.194:8666/auth',
realm: 'oneRealm',
clientId: 'main'
});
//this does not work as it can't find the keycloak.json file under WEB-INF
//var kc = Keycloak('./keycloak.json');
kc.init().success(function () {
console.log("kc.idToken.preferred_username: " + kc.idToken.preferred_username);
alert(JSON.stringify(kc.tokenParsed));
var authenticatedUser = kc.idTokenParsed.name;
console.log(authenticatedUser);
}).error(function () {
window.location.reload();
});
I assume it would be fairly common that web apps need to retrieve current user info. Anyone knows why the above code didn't work?
Thanks.
<script src="http://localhost:8080/auth/js/keycloak.js" type="text/javascript"></script>
<script type="text/javascript">
const keycloak = Keycloak({
"realm": "yourRealm",
"auth-server-url": "http://localhost:8080/auth",
"ssl-required": "external",
"resource": "yourRealm/keep it default",
"public-client": true,
"confidential-port": 0,
"url": 'http://localhost:8080/auth',
"clientId": 'yourClientId',
"enable-cors": true
});
const loadData = () => {
console.log(keycloak.subject);
if (keycloak.idToken) {
document.location.href = "?user="+keycloak.idTokenParsed.preferred_username;
console.log('IDToken');
console.log(keycloak.idTokenParsed.preferred_username);
console.log(keycloak.idTokenParsed.email);
console.log(keycloak.idTokenParsed.name);
console.log(keycloak.idTokenParsed.given_name);
console.log(keycloak.idTokenParsed.family_name);
} else {
keycloak.loadUserProfile(function() {
console.log('Account Service');
console.log(keycloak.profile.username);
console.log(keycloak.profile.email);
console.log(keycloak.profile.firstName + ' ' + keycloak.profile.lastName);
console.log(keycloak.profile.firstName);
console.log(keycloak.profile.lastName);
}, function() {
console.log('Failed to retrieve user details. Please enable claims or account role');
});
}
};
const loadFailure = () => {
console.log('Failed to load data. Check console log');
};
const reloadData = () => {
keycloak.updateToken(10)
.success(loadData)
.error(() => {
console.log('Failed to load data. User is logged out.');
});
}
keycloak.init({ onLoad: 'login-required' }).success(reloadData);
</script>
simple javascript client authentication no frameworks.
for people who are still looking...
Your code asks the Keycloak client library to initialize, but it doesn't perform a login of the user or a check if the user is already logged in.
Please see the manual for details: http://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter
What your probably want to do:
Add check-sso to the init to check if the user is logged in and to retrieve the credentials keycloak.init({ onLoad: 'check-sso' ... }). You might even use login-required.
Make sure that you register a separate client for the front-end. While the Java backend client is of type confidential (or bearer only), the JavaScript client is of type public.
You find a very minimal example here: https://github.com/ahus1/keycloak-dropwizard-integration/blob/master/keycloak-dropwizard-bearer/src/main/resources/assets/ajax/app.js
Alternatively you can register a callback for onAuthSuccess to be notified once the user information has been retrieved.
Once you use Keycloak in the front-end, you will soon want to look in bearer tokens when calling REST resources in the backend.
You might have solved the problem by this time. I hope this answer help rest of the people in trouble.
when you use JavaScript Adopter
Below javascript should be added in of html page.
<script src="http://localhost:8080/auth/js/keycloak.js"></script>
<script>
/* If the keycloak.json file is in a different location you can specify it:
Try adding file to application first, if you fail try the another method mentioned below. Both works perfectly.
var keycloak = Keycloak('http://localhost:8080/myapp/keycloak.json'); */
/* Else you can declare constructor manually */
var keycloak = Keycloak({
url: 'http://localhost:8080/auth',
realm: 'Internal_Projects',
clientId: 'payments'
});
keycloak.init({ onLoad: 'login-required' }).then(function(authenticated) {
alert(authenticated ? 'authenticated' : 'not authenticated');
}).catch(function() {
alert('failed to initialize');
});
function logout() {
//
keycloak.logout('http://auth-server/auth/realms/Internal_Projects/protocol/openid-connect/logout?redirect_uri=encodedRedirectUri')
//alert("Logged Out");
}
</script>
https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter Reference Link.
Note : Read the comments for 2 methods of adding json credentials.

Microsoft Graph API - 403 Forbidden for v1.0/me/events

I'm building a page with numerous calls to Microsoft Graph to different end points: to get OneDrive files, emails, user properties, etc.
The one call that does not work is to get the current user's calendar events. The end point I'm using is https://graph.microsoft.com/v1.0/me/events. The response is 403 Forbidden.
According to the Microsoft documentation here the application needs Calendars.Read or Calendars.ReadWrite permissions. I checked both of these under delegated permissions and still the same problem. I then ticked all 51 permission scopes in Azure AD for this app, and still the same problem.
I also tried creating a new app in Azure AD, but this did not help.
How can I use Microsoft Graph to get back the current user's calendar events? What am I missing?
EDIT:
I'm using ADAL.js for authentication. This is the code I have in my own doAuth function that takes in the client ID of the application.
function doAuth(clientId) {
var variables = {
// Domain of Azure AD tenant
azureAD: // the appropriate URL,
// ClientId of Azure AD application principal
clientId: clientId,
// Name of SharePoint tenant
sharePointTenant: // the appropriate URL
}
// Create config and get AuthenticationContext
window.config = {
tenant: variables.azureAD,
clientId: variables.clientId,
postLogoutRedirectUri: window.location.origin,
endpoints: {
graphApiUri: "https://graph.microsoft.com",
sharePointUri: "https://" + variables.sharePointTenant + ".sharepoint.com",
},
cacheLocation: "localStorage"
}
var authContext = new AuthenticationContext(config);
var isCallback = authContext.isCallback(window.location.hash);
authContext.handleWindowCallback();
if (isCallback && !authContext.getLoginError()) {
window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST);
}
var user = authContext.getCachedUser();
var token = authContext.getCachedToken(clientId);
if (!user || !token)
authContext.login();
return authContext
}
It sounds like you've changed the scopes assigned to the application. When this happens you also need to have user's reauthorize using those new scopes. To do this, add &prompt=consent to the query string of your initial ODATA redirect. This will force your new scopes to be presented to the user for authorization.
You can trigger this in the ADAL.js library using the extraQueryParameter parameter in your configuration:
// Create config and get AuthenticationContext
window.config = {
tenant: variables.azureAD,
clientId: variables.clientId,
postLogoutRedirectUri: window.location.origin,
endpoints: {
graphApiUri: "https://graph.microsoft.com",
sharePointUri: "https://" + variables.sharePointTenant + ".sharepoint.com",
},
cacheLocation: "localStorage",
extraQueryParameter: "prompt=consent"
}
In the end I wasn't able to figure this out and ended up using the Exchange API instead of Graph for mail, calendar and tasks (tasks would have required Exchange API anyway, since this is only currently available in the beta Graph API).

Creating users in tenant using Microsoft Office 365 API and link it to chrome Id

I manually created a user in Azure active directory for my project and I am able to get the users. I made a chrome extension and GCM provides me a ID which I want to be linked with the microsoft account.
So for each user, I want a GCM id (got this part) and an Azure AD Id linked together.
I was doing the following:
router.route('/users')
// create a user accessed at POST http://localhost:8080/api/users)
.post(function(req, res) {
// Get an access token for the app.
auth.getAccessToken().then(function (token) {
console.log(token)
var user = new User({
officeId: token,
name : req.body.name,
email :req.body.email,
chromeId : req.body.chromeId
});
user.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'User created!' });
});
});
});
However, what this does is take the auth token id, chromeId, name and email and just adds it to my mongoose database.
What can I do differently in order to get what I want to achieve? My teammate says what I am doing is correct but I checked the Azure AD and I don't see my user authorized there.
Btw, in the front-end, I ask a user to give their microsoft email and name.
Also, I merged my code with the code found here https://github.com/OfficeDev/O365-Nodejs-Microsoft-Graph-App-only
// #name getAccessToken
// #desc Makes a request for a token using client credentials.
auth.getAccessToken = function () {
var deferred = Q.defer();
// These are the parameters necessary for the OAuth 2.0 Client Credentials Grant Flow.
// For more information, see Service to Service Calls Using Client Credentials (https://msdn.microsoft.com/library/azure/dn645543.aspx).
var requestParams = {
'grant_type': 'client_credentials',
'client_id': config.clientId,
'client_secret': config.clientSecret,
'resource': 'https://graph.microsoft.com'
};
// Make a request to the token issuing endpoint.
request.post({url: config.tokenEndpoint, form: requestParams}, function (err, response, body) {
var parsedBody = JSON.parse(body);
if (err) {
deferred.reject(err);
} else if (parsedBody.error) {
deferred.reject(parsedBody.error_description);
} else {
// If successful, return the access token.
deferred.resolve(parsedBody.access_token);
}
});
return deferred.promise;
};
If you want to create use in your AAD, you can leverage the Microsoft Graph API: Create User, which is not implemented in your code or the graph.js code at github repository.
You need to implement the function yourself like:
Additionally, it seems that we have to generate the access token in Authorization Code Grant Flow to complete the operation. As in my test, I got the Authorization_RequestDenied error when I use the app-only flow access token to authorize the operation, and the graph server returned me the message:
"message": "Insufficient privileges to complete the operation."
you can refer to https://github.com/OfficeDev/O365-Nodejs-Microsoft-Graph-Connect/ for the sample.

Categories

Resources