Skip to content

Instantly share code, notes, and snippets.

@hakimio
Last active June 26, 2020 07:05
Show Gist options
  • Select an option

  • Save hakimio/be2b028d83ab4ec2f232f77e2e47a0ef to your computer and use it in GitHub Desktop.

Select an option

Save hakimio/be2b028d83ab4ec2f232f77e2e47a0ef to your computer and use it in GitHub Desktop.
AWS Cognito Google authentication service
export interface AuthenticationTokens {
id_token: string;
access_token: string;
refresh_token: string;
expires_in: number;
token_type: string;
}
import {environment} from '../../../environments/environment';
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {Observable, of} from 'rxjs';
import {AuthenticationTokens} from './google-auth.model';
import {map} from 'rxjs/operators';
import {alert} from 'devextreme/ui/dialog';
@Injectable()
export class GoogleAuthService {
private readonly ALREADY_FOUND_ERROR = 'Already found an entry for username';
private readonly INVALID_STATE_ERROR = 'Invalid state for';
private readonly USER_NOT_FOUND_ERROR = 'User not found';
private readonly ERROR_CODE = 'invalid_request';
private readonly OAUTH_SCOPES = ['email', 'openid', 'profile', 'aws.cognito.signin.user.admin'];
constructor(
private httpClient: HttpClient
) {}
redirectToGoogleLogin() {
const userPoolConfig = environment.cognitoUserPool,
appDomain = userPoolConfig.AppWebDomain,
clientId = userPoolConfig.ClientId,
identityProvider = 'Google',
responseType = 'code',
redirectUri = encodeURIComponent(location.origin),
scope = encodeURIComponent(this.OAUTH_SCOPES.join(' ')),
fullUrl = `${appDomain}/oauth2/authorize` +
`?redirect_uri=${redirectUri}` +
`&response_type=${responseType}` +
`&client_id=${clientId}` +
`&identity_provider=${identityProvider}` +
`&scope=${scope}`;
window.location.replace(fullUrl);
}
getTokens(): Observable<AuthenticationTokens | null> {
const searchParams = (new URL(location.href)).searchParams,
errorDescription = searchParams.get('error_description'),
errorCode = searchParams.get('error'),
code = searchParams.get('code');
if (errorCode === this.ERROR_CODE) {
this.processTheError(errorDescription);
return of(null);
}
if (!code) {
return of(null);
}
return this.getAuthTokens(code);
}
private getAuthTokens(code: string): Observable<AuthenticationTokens> {
const formData = new URLSearchParams(),
cognitoConfig = environment.cognitoUserPool,
url = `${cognitoConfig.AppWebDomain}/oauth2/token`;
formData.set('grant_type', 'authorization_code');
formData.set('client_id', cognitoConfig.ClientId);
formData.set('redirect_uri', location.origin);
formData.set('code', code);
return this.httpClient
.post(url, formData.toString(), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.pipe(
map(
response => <AuthenticationTokens> response
)
);
}
private processTheError(errorDescription: string) {
// Following is a workaround for AWS Cognito bug. More info:
// https://stackoverflow.com/questions/47815161/cognito-auth-flow-fails-with-already-found-an-entry-for-username-facebook-10155
// https://forums.aws.amazon.com/thread.jspa?threadID=267154
// https://github.com/aws-amplify/amplify-js/issues/565
if (errorDescription.includes(this.ALREADY_FOUND_ERROR)) {
this.redirectToGoogleLogin();
} else if (errorDescription.includes(this.INVALID_STATE_ERROR)) {
alert('Please login normally to confirm the user', 'User not confirmed');
} else if (errorDescription.includes(this.USER_NOT_FOUND_ERROR)) {
alert('Your email has to be approved by administrator first', 'Invalid email');
} else {
alert('Unknown error. Please contact a developer', 'Error');
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment