This app shows a user authentication strategy using OAuth 2.0 and OpenID Connect. Sign up to lead is an alternative to SSO sign up / sign in for products which can not be instantly deployed. It is not the preferred integration method, but it is acceptable for products that require an extensive pre-sales / onboarding process or deal with physical or non-cloud based products.
This sample project is an implementation of the OAuth 2, Modified Sign Up with Xero flow which is documentated in the Xero developer portal.
The following steps are the core pieces of code you will need to implement this in any application.
This will look something like:
https://login.xero.com/identity/connect/authorize?client_id=<CLIENT_ID>&scope=openid profile email&response_type=code&redirect_uri=<CALLBACK_URI>
- openid profile email: These are Xero's supported OIDC scopes. They will return a JWT called
id_token
which you can Base64Url decode to utilize the user's information
Note: These scopes to do NOT authorise API access, they ONLY request identity details for the user.
In the same route that matches the authorization url and the app settings in your Xero App Dashboard, you will need to catch the authorization flow temporary code and exchange for token_set
Callback URL: <CALLBACK_URI>?code=ASDADSADASDASD&scope=openid%20profile%20email
In this example we are using the xero-node SDK which has a helper to do this exchange.
const tokenSet = await xero.apiCallback(responseUrl);
The SDK also handles this under the hood with an OIDC Certified library called node-openid-client which does a sequence of cryptographic checks to ensure the token is valid and has not been tampered with.
await this.validateIdToken(tokenset, checks.nonce, 'authorization', checks.max_age, checks.state);
Once validated we can decode the JWT and access the user data within for use in our user management & login code.
const decodedIdToken = jwtDecode(tokenSet.id_token)
const userParams = {
firstName: decodedIdToken.given_name,
lastName: decodedIdToken.family_name,
email: decodedIdToken.email,
xero_userid: decodedIdToken.xero_userid,
decoded_id_token: decodedIdToken,
token_set: tokenSet,
...
}
Optional: This step is optional. You could save the user data to a temporary session / cookie, rather than a database. You could also simply pre-populate the form with the user data, and save it only upon submission of the form.
Now that we have verified user data out of our id_token
we can lookup to see if that user already exists or not. If they do, we update any incoming data like a name change, and if not we create a new user record in our database and log them, setting a secure signed cookie variable that will persist for the sign up period.
const user = await User.findOne({where: { email: decodedIdToken.email }})
if (user) {
await user.update(userParams).then(updatedRecord => {
console.log(`UPDATED user ${JSON.stringify(updatedRecord.email,null,2)}`)
return updatedRecord
})
} else {
await User.create(userParams).then(createdRecord => {
console.log(`CREATED user ${JSON.stringify(createdRecord.email,null,2)}`)
return createdRecord
})
}
res.cookie('recentSession', recentSession, { signed: true, maxAge: 1 * 60 * 60 * 1000 }) // 1 hour
Now that the user has authenticated with Xero's identity service, you can pre-populate a sign up form in order to collect additional details which Xero's identity service & API do not provide.
Details provided in the form are saved against the user in the database.
While this is a fully working example, you'll likely want to throw in another step here. The sign up data is saved to the database. You'll likely want to send this data to a CRM, workflow tool, or just email it to the sales team. Either way, that should be easy enough to add.
To contribute or extend to this repo get running locally through these steps:
- Install postgres
On mac I recommend using homebrew to install. For windows or Ubuntu please follow postgres' guides.
Helpful guides if you get stuck:
- MacOS Install to set that up
- Install sequelize-cli
npm install --save-dev sequelize-cli
- Create a Postgres user and database
To setup your initial PG user I reccomend reading https://medium.com/coding-blocks/creating-user-database-and-adding-access-on-postgresql-8bfcd2f4a91e
- Login to Xero Developer center https://developer.xero.com/myapps and create a new API application
- Create a
.env
file in the root of your project - Replace the variables in .env
CLIENT_ID=...
CLIENT_SECRET=...
REDIRECT_URI=...
DATABASE=...
DATABASE_USER=...
DATABASE_PASSWORD=...
PORT=5000
yarn
andnpm
are interchangeable
npm install
npm start
open http://localhost:5000/