1
0

google-authentication-strategy.ts 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import {
  2. AuthenticationStrategy,
  3. Customer,
  4. ExternalAuthenticationMethod,
  5. Injector,
  6. RequestContext,
  7. RoleService,
  8. User,
  9. } from '@vendure/core';
  10. import { OAuth2Client } from 'google-auth-library';
  11. import { TokenPayload } from 'google-auth-library/build/src/auth/loginticket';
  12. import { DocumentNode } from 'graphql';
  13. import gql from 'graphql-tag';
  14. import { Connection } from 'typeorm';
  15. export type GoogleAuthData = {
  16. token: string;
  17. };
  18. export class GoogleAuthenticationStrategy implements AuthenticationStrategy<GoogleAuthData> {
  19. readonly name = 'google';
  20. private client: OAuth2Client;
  21. private connection: Connection;
  22. private roleService: RoleService;
  23. constructor(private clientId: string) {
  24. this.client = new OAuth2Client(clientId);
  25. }
  26. init(injector: Injector) {
  27. this.connection = injector.getConnection();
  28. this.roleService = injector.get(RoleService);
  29. }
  30. defineInputType(): DocumentNode {
  31. return gql`
  32. input GoogleAuthInput {
  33. token: String!
  34. }
  35. `;
  36. }
  37. /**
  38. * Implements https://developers.google.com/identity/sign-in/web/backend-auth
  39. */
  40. async authenticate(ctx: RequestContext, data: GoogleAuthData): Promise<User | false> {
  41. const ticket = await this.client.verifyIdToken({
  42. idToken: data.token,
  43. audience: this.clientId,
  44. });
  45. const payload = ticket.getPayload();
  46. if (!payload) {
  47. return false;
  48. }
  49. const user = await this.connection
  50. .getRepository(User)
  51. .createQueryBuilder('user')
  52. .leftJoinAndSelect('user.authenticationMethods', 'authMethod')
  53. .where('authMethod.externalIdentifier = :sub', { sub: payload.sub })
  54. .getOne();
  55. if (user) {
  56. return user;
  57. }
  58. return this.createNewCustomerAndUser(payload);
  59. }
  60. private async createNewCustomerAndUser(data: TokenPayload) {
  61. const customerRole = await this.roleService.getCustomerRole();
  62. const newUser = new User({
  63. identifier: data.email,
  64. roles: [customerRole],
  65. verified: data.email_verified || false,
  66. });
  67. const authMethod = await this.connection.manager.save(
  68. new ExternalAuthenticationMethod({
  69. externalIdentifier: data.sub,
  70. provider: this.name,
  71. }),
  72. );
  73. newUser.authenticationMethods = [authMethod];
  74. const savedUser = await this.connection.manager.save(newUser);
  75. const customer = await this.connection.manager.save(
  76. new Customer({
  77. emailAddress: data.email,
  78. firstName: data.given_name,
  79. lastName: data.family_name,
  80. user: savedUser,
  81. }),
  82. );
  83. return savedUser;
  84. }
  85. }