Amsel
Verify a Google access token or a Microsoft id_token (for a specific tenant application) and extract its user object in your node backend.
Installation
Install Amsel using yarn
:
yarn add @jubileesoft/amsel
Or npm
:
npm install @jubileesoft/amsel
Configuration
// typescript example
import amsel, { GoogleConfig } from '@jubileesoft/amsel';
const config: GoogleConfig = {
appClientId: 'my-client-id-from-google'
};
amsel.initializeGoogle(config);
Make sure to call initializeGoogle
with the appropriate config before validating any tokens.
Microsoft
// typescript example
import amsel, { MicrosoftConfig } from '@jubileesoft/amsel';
const config: MicrosoftConfig = {
tenantId: 'my-tenant-id-where-the-app-is-registered',
appId: 'my-app-id'
};
amsel.initializeMicrosoft(config);
Make sure to call initializeMicrosoft
with the appropriate config before validating any tokens.
Usage
When you process a client-request in your node backend (e.g. from a REST call or GraphQL query), you can use the function verifyAccessTokenFromGoogle
or verifyAccessTokenFromMicrosoft
to verify the access token or id_token included in the authorization header of the request.
// typescript example
import { GoogleUser } from '@jubileesoft/amsel';
const user: Promise<GoogleUser | null> = await amsel.verifyAccessTokenFromGoogle(
req.headers.authorization // should look like "Bearer ...something..."
);
The promise either returns null if the token could not be verified or a user object that looks like this:
// user object GoogleUser
{
access_type:"online",
aud:"4xxxxxxxxxx3-qhjjmmug094kpv9b4iu35g65aa34v4u0.apps.googleusercontent.com",
azp:"4xxxxxxxxxx3-qhjjmmug094kpv9b4iu35g65aa34v4u0.apps.googleusercontent.com",
email:"peter.lustig@gmail.com",
email_verified:"true",
exp:"1589920584",
expires_in:"3502",
scope:"openid https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile",
sub:"10769150350006150715113082367"
}
// user object MicrosoftUser
{
aio:"AUQAu/8PAAAA59n9QoJuFmNVSyERuiK7TLcv9rnW1t4GvzgKdY2rWLcp2KpmeklVU1P7epwwSofFb3BC18Myp6JRkVnkmlntHw=="
at_hash:"EtHCDTh4GhOq--Txo2gViw"
aud:"53d235e2-66d1-4312-92d0-c34ff0aa546d"
email:"Peter.Lustig@wdr.com"
exp:1590142952
iat:1590139052
iss:"https://login.microsoftonline.com/08fcd60a-b77c-4be0-aa28-495621e88734/v2.0"
name:"Lustig, Peter"
nbf:1590139052
nonce:"678910"
oid:"569a1735-07de-43a3-a72d-d5cf6cadf76f "
preferred_username:"Peter.Lustig@wdr.com"
sub:"CLq_tBCeazZek3p8OLoZbngt_V54f44m7hTzrdofaOM"
tid:"08fcd60a-b77c-4be0-aa28-495621e88734"
uti:"3s14Gf_EwUiKeW66hmwrAA"
ver:"2.0"
}
So, whenever you get a user object you know that the token is currently still valid.
GraphQL Apollo Server v2 example
The following example shows how an instance of the ApolloServer could be created while putting the user object on the context.
import amsel from '@jubileesoft/amsel';
const server = new ApolloServer({
typeDefs,
resolvers,
context: async ({ req }) => {
const notAuthenticated = { user: null };
try {
const user = await amsel.verifyAccessTokenFromGoogle(
req.headers.authorization
);
return { user };
} catch (e) {
return notAuthenticated;
}
}
});
The user object on the context is then available within any resolvers where you can decide what to do.