Auth helpers for apollo server using OneGraph AuthGuardian
You can use AuthGuardian by OneGraph to handle all of your authentication and
permission needs in your Apollo server.
Each rule consists of two parts: conditions and effects.
An example of a rule condition might be,
> "When this user is a member of organization X on GitHub AND this user has made at least one commit to the repository repo-owner/repo-name".
OneGraph knows how to query each of the services to find out if the condition
has been met automatically!
When all of the conditions for a rule are met, the effects are run. An effect
might be:
> Set the user.id to the user's GitHub user-id, and add "admin" to the list of user.roles
So the full rule would read:
> "When this user is a member of organization X on GitHub AND this user has made at least one commit to the repository repo-owner/repo-name".
> Then set the user.id to the user's GitHub user-id AND add "admin" to the list of user.roles AND add a Netlify role of "developer"
If this rule passed after a user logged in via GitHub, OneGraph would generate a
full, signed JWT for use in your GraphQL resolvers:
```
{
"iss": "OneGraph",
"aud": "https://serve.onegraph.com/dashboard/app/00000000-0000-0000-0000-000000000000",
"iat": 1566594200,
"exp": 1566680600,
"user": {
"id": 35296,
"roles": [
"admin"
]
},
"app_metadata": {
"authorization": {
"roles": [
"developer"
]
}
}
}
``
npm install --save onegraph-apollo-server-author
yarn add onegraph-apollo-server-auth
2. Use the custom directives
There are two customer directives implemented by onegraph-apollo-server-auth, @isAuthencated and @hasRoles:
``
directive @isAuthenticated on QUERY | FIELD_DEFINITION
directive @hasRole(oneOf: [String!]) on QUERY | FIELD_DEFINITION
#### @isAuthenticated
Any field that has this directive added to is will always check in the JWT that
a value is present at user.id. If not, the user has not authenticated (that
is, has not logged into any service), and the field will return null, and an
error message will be added to the response.
``
type Query {
companies : [Company] @isAuthenticated
}
#### @hasRole
Any field with this directive added will check in the JWT at the path
user.roles to make sure that the user has been granted a role that's required
to view this field.
``
type Company {
id: String!
name: String @hasRole(oneOf: ["visitor"])
accountBalance: Int! @hasRole(oneOf: ["admin"])
}
In this case, any user will be able to query for Company ids, but thevisitor
AuthGuardian rules must have granted this user the role to view thename
Company , and the admin role to view the Company accountBalance.
#### Put it all together!
`
const { ApolloServer } = require("apollo-server-express");
const { schema } = require("./schema.js");
const {
extractBearerToken,
hasRoleDirective,
isAuthenticatedDirective,
makeOneGraphJwtVerifier
} = require("onegraph-apollo-server-auth");
const verifyJwt = makeOneGraphJwtVerifier(appId);
const server = new ApolloServer({
typeDefs: schema,
resolvers,
schemaDirectives: {
hasRole: hasRoleDirective,
isAuthenticated: isAuthenticatedDirective
},
context: async incoming => {
const token = extractBearerToken(incoming.req);
if (!token) {
return { jwt: null };
}
try {
const decoded = await verifyJwt(token).catch(rejection =>
console.warn(JWT verification failed: , rejection)`
);
return { jwt: decoded };
} catch (rejection) {
console.warn(rejection);
return { jwt: null };
}
}
});
And that's it! With just a few bits of annotation to your schema and a few
minutes to configure the AuthGuardian rules, your entire authentication and
permissions system can be taken care of securely!
Install the onegraph-auth package on your client:
``
npm install --save onegraph-author
yarn add onegraph-auth
Instantiate the auth client in the browser (with the same APP_ID you used to
configure AuthGuardian):
`
import OneGraphAuth from 'onegraph-auth';
const APP_ID = YOUR_APP_ID;
const auth = new OneGraphAuth({
appId: APP_ID,
});
`
And log in your user (in this case via github):
```
auth
.login('github')
.then(() => {
auth.isLoggedIn('github').then(isLoggedIn => {
if (isLoggedIn) {
console.log('Successfully logged in to GitHub');
} else {
console.log('Did not grant auth for GitHub');
}
});
})
.catch(e => console.error('Problem logging in', e));
That's it! At the end of that flow, all of your AuthGuardian rules will have
run, and the user will have a JWT that reflects their authentication and
permissions for your API!