Skip to content

Instantly share code, notes, and snippets.

@jeff-auth0
Last active March 24, 2023 03:50
Show Gist options
  • Save jeff-auth0/1ac8bdc061589c6b1e962650cb9fb80f to your computer and use it in GitHub Desktop.
Save jeff-auth0/1ac8bdc061589c6b1e962650cb9fb80f to your computer and use it in GitHub Desktop.
Trickle user migration to Auth0 from Azure B2C AD
/**
*
* NOTE: THIS SCRIPT IS A GUIDE ONLY AND IT IS NOT TESTED IN A PRODUCTION ENVIRONMENT
*
* HOW:
* 1. Azure ROPC (Resource Owner Password Credentials) flow will be used to migrate users from Azure B2C AD to Auth0.
* 2. Lazy migration needs to be enable on your Auth0 Database. https://auth0.com/docs/manage-users/user-migration/configure-automatic-migration-from-your-database
*
*
* References:
* https://docs.microsoft.com/en-us/azure/active-directory-b2c/add-ropc-policy?tabs=app-reg-ga&pivots=b2c-user-flow#ropc-flow-notes
* https://auth0.com/docs/authenticate/database-connections/custom-db/overview-custom-db-connections
* https://auth0.com/docs/authenticate/database-connections/custom-db/templates/login
*
* Prerequisites:
* 1. Register an App in Azure B2C AD for this migration - Follow the guide in ROPC doc above.
* 2. Register an API ( an existing API can be used ) - this is required to get id token.
* 3. Add API Permissions for the application. Copy the URL of the scope
*
* TODO:
* 1. Verify JWT token.
*
*
*/
function login(email, password, callback) {
let profile = {};
let jwt_decode = require("jwt-decode");
let request = require("request");
const options = {
url: "<Azure ROPC Token Endpoint>",
formData: {
username: email,
password: password,
grant_type: "password",
scope: "openid <scope_url from step 3>",
client_id: "<Client Id of an registered App in Azure B2C>",
response_type: "token id_token",
},
headers: [{
name: "content-type",
value: "application/x-www-form-urlencoded",
}, ],
};
request.post(options, (err, httpResponse, body) => {
if (err) {
return callback(
new WrongUsernameOrPasswordError(email, "Something went wrong"),
);
}
const parsed = JSON.parse(body);
if (parsed && parsed.id_token) {
var decoded = jwt_decode(parsed.id_token);
// Find more profile attributes:
// https://auth0.com/docs/authenticate/database-connections/custom-db/templates/login#callback-profile-parameter-example-)
profile = {
user_id: decoded.sub,
email,
family_name: decoded.family_name,
given_name: decoded.given_name,
};
// Invoke Graph API /me endpoint to get extended attributes
request.get({
url: "https://graph.microsoft.com/v1.0/me",
headers: [{
name: "content-type",
value: "application/x-www-form-urlencoded",
Authorization: `Bearer ${parsed.id_token}`,
}, ],
},
(err, httpResponse, body) => {
if (err) {
return callback(
new WrongUsernameOrPasswordError(
email,
"Cannot fetch extended profile attribute",
),
);
}
const extended_profile = JSON.parse(body);
if (!extended_profile) {
profile.app_metadata = {
key: extended_profile.name_of_attribute,
};
}
},
);
return callback(null, profile);
} else {
return callback(new Error("Unable to get token from Idp"));
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment