Skip to main content

Implementing login and signup on Angular with Cryptr

Cryptr - Angular illustration

Beginner Angular Tutorial with Cryptr Authentication

Angular v9 to v113min

Learn how to build an Angular application that includes Cryptr authentication.

In this tutorial, weโ€™ll walk you through the process, step-by-step, to build an Angular application from scratch and secure your application by implementing Cryptr authentication. You'll just need to have a code editor (I personally use VS Code) and access to the terminal in order to complete this tutorial.

Let's get started! ๐Ÿ˜‰

1. Get the Starter Applicationโ€‹

๐Ÿ›  Clone the shark-academy-angular-template repository to get started:

git clone https://github.com/cryptr-examples/shark-academy-angular-template.git

๐Ÿ›  Once youโ€™ve cloned the repo, go to shark-academy-angular-template with command:

cd shark-academy-angular-template

๐Ÿ›  Install the Angular project dependencies with yarn or yarn install (or npm i or npm install)

๐Ÿ›  Finally, run the Angular application with ng serve or yarn start (or npm start)

2. Application Keysโ€‹

Create application with Cryptrโ€‹

You're going to use Cryptrโ€™s authentication service to do the tutorial.

๐Ÿ› ๏ธ๏ธ First, sign up for a free Cryptr account here. Once you're registered, you'll be taken to the Cryptr Onboarding to create your application

Rendering Rendering

๐Ÿ› ๏ธ๏ธ You can then create your application by following the onboarding steps.

Rendering

Once you've completed all the funnel, after the processing steps, you arrive on the homepage of the back-office where you have access to various guides that will help you. They will depend on the choices of technology you have made in the funnel.

Rendering

๐Ÿ› ๏ธ๏ธ You can get your environment configuration by first clicking on ยซ applications ยป in the left menu, then by clicking on the application you will have created. A modal will appear and this is where you may copy/paste your environment variables.

Rendering Rendering

Add your Cryptr credentialsโ€‹

๐Ÿ›  Complete the content of src/environments/environment.ts.

You may copy/paste this code, and make sure to replace YOUR_CLIENT_ID and YOUR_DOMAIN by yours:

src/environments/environment.ts
export const environment = {
production: false,
cryptrConfig: {
audience: 'http://localhost:4200',
tenant_domain: 'YOUR_DOMAIN',
client_id: 'YOUR_CLIENT_ID',
region: 'eu',
default_redirect_uri: 'http://localhost:4200',
httpInterceptor: {
apiRequestsToSecure: ['http://localhost:5000/*'],
},
telemetry: false,
},
resource_server_url: 'http://localhost:5000',
}
API URL

You can include an API URL in httpInterceptor and resource_server_url that does not exist yet. If you don't have an API, that's OK, there just has to be a URL, even if it is not used. Later on when you create an API, you can update the URL in your environment file

Where can I find my tenant domain and my client ID?

You can get your tenant domain and your client id in the Cryptr back-office, in the modal that is displayed when you select your application.

Rendering

Restart the terminal

Make sure to restart your shell/terminal when you modify the environment file

3. Set up the Cryptr Angular SDKโ€‹

Installationโ€‹

๐Ÿ›  First, you need to install our package as dependency with your favourite package manager:

npm install @cryptr/cryptr-angular

or

yarn add @cryptr/cryptr-angular

Before implementing our sign actions, you need to update your app module to import the SDK features (authentication, security routing, request authentication).

๐Ÿ›  Import AuthModule and environment in the @NgModule definition in src/app/app.module.ts as follows:

src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './pages/home/home.component';
import { ProfileComponent } from './pages/profile/profile.component';
import { NavComponent } from './components/nav/nav.component';
// 1. Import AuthModule and environment
import { AuthModule } from '@cryptr/cryptr-angular'
import { environment } from 'src/environments/environment';

@NgModule({
declarations: [AppComponent, HomeComponent, ProfileComponent, NavComponent],
imports: [
BrowserModule,
AppRoutingModule,
// 2. Add in @NgModule definition
AuthModule.forRoot(environment.cryptrConfig)
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}

๐Ÿ›  Import HttpClientModule and HTTP_INTERCEPTOR and add { provide: HTTP_INTERCEPTORS, useClass: AuthHttpInterceptor, multi: true } to providers:

src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './pages/home/home.component';
import { ProfileComponent } from './pages/profile/profile.component';
import { NavComponent } from './components/nav/nav.component';
import { AuthModule, AuthHttpInterceptor } from '@cryptr/cryptr-angular'
// 1. Import HttpClientModule and HTTP_INTERCEPTOR
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'
import { environment } from 'src/environments/environment';

@NgModule({
declarations: [AppComponent, HomeComponent, ProfileComponent, NavComponent],
imports: [
BrowserModule,
AppRoutingModule,
// 2. Add HttpClientModule in @NgModule definition
HttpClientModule,
AuthModule.forRoot(environment.cryptrConfig)
],
providers: [
// 3. Modify providers
{ provide: HTTP_INTERCEPTORS, useClass: AuthHttpInterceptor, multi: true }
],
bootstrap: [AppComponent],
})
export class AppModule {}

At this point, your app should run and be prepared to handle end-user session with Cryptr.

App routing updateโ€‹

๐Ÿ›  Import AuthGuard and add canActivate: [AuthGuard] in src/app/app-routing.module.ts to every path you want to secure (if there is no active session, end-user will be redirected to Cryptr sign form):

src/app/app-routing.module.ts
import { ProfileComponent } from './pages/profile/profile.component';
// 1. Import AuthGuard
import { AuthGuard } from '@cryptr/cryptr-angular';

const routes: Routes = [
{
path: '',
component: HomeComponent,
},
{
path: 'profile',
component: ProfileComponent,
// 2. Add canActivate: [AuthGuard] to secure profile path
canActivate: [AuthGuard]
}
];

@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }

This update will allow your app to handle the end of the authentication process from Cryptr.

You are ready to implement the authentication flow.

4. Add user authenticationโ€‹

Signupโ€‹

๐Ÿ›  Open up home.component.ts file in the src/app/pages/home/ and paste the following code:

src/app/pages/home/home.component.ts
import { Component, OnInit } from '@angular/core';
// 1. Import AuthService
import { AuthService } from '@cryptr/cryptr-angular';

@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
// 2. Add state for authentication
authenticated = false;

// 3. Add AuthService in constructor
constructor(public auth: AuthService) { }

// 4. Modify ngOnInit and add currentAuthenticationObservable
ngOnInit(): void {
this.auth.currentAuthenticationObservable().subscribe((isAuthenticated: boolean) => {
this.authenticated = isAuthenticated;
});
}
// 5. Add signUpWithRedirect
signUpWithRedirect(): void {
this.auth.signUpWithRedirect();
}
}
Note
  • You can observe authentication state through currentAuthenticationObservable method.
  • signUpWithRedirect will handle Cryptr redirection to signup user.

๐Ÿ›  Next, open up home.component.html template file in src/app/pages/home/ and modify button like this:

src/app/pages/home/home.component.html
<button
*ngIf="!authenticated"
(click)="signUpWithRedirect()"
class="cursor-pointer sm:mr-8 md:mr-10"
>
<div class="rounded-md shadow">
<a
class="w-full flex items-center justify-center px-8 py-3 border border-transparent text-sm leading-6 font-bold shadow-md rounded-md uppercase text-gray-900 bg-yellow-400 hover:bg-yellow-300 focus:outline-none focus:border-yellow-500 focus:shadow-outline-yellow transition duration-150 ease-in-out md:py-3 md:text-base md:px-10"
>
Signup
</a>
</div>
</button>

Login and logoutโ€‹

๐Ÿ›  Open up nav.component.ts file in src/app/components/nav/ and paste the following code:

src/app/components/nav/nav.component.ts
import { Component, OnInit } from '@angular/core';
// 1. Import Router and AuthService
import { Router } from '@angular/router';
import { AuthService } from '@cryptr/cryptr-angular';

@Component({
selector: 'app-nav',
templateUrl: './nav.component.html',
styleUrls: ['./nav.component.scss']
})
export class NavComponent implements OnInit {
// 2. Add state for authentication
authenticated=false;
unauthenticatedPath = '/';

// 3. Add AuthService and Router in constructor
constructor(public auth: AuthService, private router: Router) {
}

// 4. Modify ngOnInit and add currentAuthenticationObservable
ngOnInit(): void {
this.auth.currentAuthenticationObservable().subscribe((isAuthenticated: boolean) => {
this.authenticated = isAuthenticated;
});
}

// 5. Add logOut
logOut(): void {
this.auth.logOut(() => {
this.router.navigateByUrl(this.unauthenticatedPath);
});
}

// 6. signInWithRedirect
signInWithRedirect(): void {
this.auth.signInWithRedirect();
}
}
Note

logOut method can process custom callback at the end of session closing.

๐Ÿ›  Next, open up nav.component.html template file in src/app/components/nav/ and modify buttons like this:

src/app/components/nav/nav.component.html
<button
*ngIf="!authenticated"
(click)="signInWithRedirect()"
type="button"
class="relative inline-flex items-center px-5 py-3 border border-transparent text-base uppercase leading-5 font-bold rounded-md text-yellow-500 shadow-md hover:shadow-xl focus:outline-none transition duration-150 ease-in-out"
>
<span>Login</span>
</button>
<button
*ngIf="authenticated"
(click)="logOut()"
type="button"
class="relative inline-flex items-center px-5 py-3 border border-transparent text-base uppercase leading-5 font-bold rounded-md text-yellow-500 shadow-md hover:shadow-xl focus:outline-none transition duration-150 ease-in-out"
>
Logout
</button>

๐Ÿ›  Run server & try to connect. Your Angular application redirects you to your sign form page, where you can sign in or sign up with an email.

SANDBOX EMAIL

You can log in with a sandbox email and we send you a magic link which should directly arrive in your personal inbox. Your sandbox email is based on your account's email. The email's structure is as follows: my-user-to-test@sandbox.my-admin-name. For example testemail@sandbox.lucas

If you are logged out and try to go to the profile page, you will be taken to the login page, which is exactly what is expected due to routing configuration!

Retrieve User informationโ€‹

Everything in our authentication is gravitating around your end-user. At some point, you may want to retrieve and display user data such as email, metadata, or other attributes attached to his authentication.

If you want to retrieve user data such as email for example, you can do it through AuthService.

๐Ÿ›  Update ProfileComponent in src/app/pages/profile/profile.component.ts with following code:

src/app/pages/profile/profile.component.ts
import { Component, OnInit } from '@angular/core';
// 1. Import AuthService
import { AuthService } from '@cryptr/cryptr-angular';

@Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.scss']
})
export class ProfileComponent implements OnInit {
// 2. Add state for authentication
authenticated = false;
// 3. Add AuthService in constructor
constructor(public auth: AuthService) {}

// 4. Modify ngOnInit and add observableAuthenticated
ngOnInit() {
this.auth.observableAuthenticated().subscribe((isAuthenticated: boolean) => {
this.authenticated = isAuthenticated
})
}

// 4. Add getUserEmail to retrieve user email
getUserEmail() : string | undefined {
let user = this.auth.getUser();
if (this.authenticated && user) {
return user.email;
}
}
}
Note

User informations are available using getUser method.

๐Ÿ›  Update the template ProfileComponent in src/app/pages/profile/profile.component.html with following code:

src/app/pages/profile/profile.component.html
<div class="py-36 bg-white">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="lg:text-center">
<p class="text-3xl leading-8 font-extrabold tracking-tight text-gray-900 sm:text-4xl">
This is a profile page
</p>
<p class="mt-4 max-w-2xl text-xl text-gray-500 lg:mx-auto">
{{ getUserEmail() }}
</p>
</div>
</div>
</div>

You can now see the user's email address in the profile page when you're logged in!

Congratulations if you made it to the end! Now, let's recap everything that has been covered in the tutorial:

  • Integrated user authentication with Cryptr
  • Protecting routes
  • Simple sign up, login and logout
  • Getting user profile information

I hope this was helpful, and thanks for reading! ๐Ÿ™‚

What's next ?

After allowing the end-user to authenticate to your Angular Application, you may want to secure the data you want to display to him?

In the next article we will speak about how to secure your API request to your Resource server