AzPark: SWA - Azure Static Web Apps Authentication in Angular application

Hey folks!, In this blog let’s see how to implement authentication flow in our Angular application and also will cover how to emulate this flow in our local development.


SWA provides a streamlined authentication experience. By default , you have access to three providers that is pre-configured or you do have option to register a custom provider

Standard plan
Custom authentication however is only available in Standard Plan

By default Azure provides us with two built-in roles

  • anonymous
  • authenticated

We will cover role management in a seperate blog. In this blog let’s try to focus on authentication based on default providers. Below are the default providers pre-configured

  • Microsoft Active Directory
  • GitHub
  • Twitter

Authorization provider Login route
Azure Active Directory ./auth/login/aad
GitHub ./auth/login/github
Twitter ./auth/login/twitter

SWA provides authentication-related user information via a direct-access endpoint and to API functions. We will see how to authorize our backend in a seperate blog.

The direct-access endpoint is a utility API that exposes user information and it isn’t subject to cold start delays that are associated with serverless architecture.

1
2
3
4
5
6
{
  "identityProvider": "aad",
  "userId": "d75b260a64504067bfc5b2905e3b8182",
  "userDetails": "username",
  "userRoles": ["anonymous", "authenticated"]
}

We can send a GET request to the ./auth/me route that provides us with the above client principal data. For the logged-in users , the response is as same as above json , if request is from unauthenticated users then it returns null.

In your angular application expose below method in a service

1
2
3
login() : any{        
    return this.http.get('/.auth/me');  
  }

Those who are familiar with Angular frontend development should have came across this AuthGuards . It is a concept that is used to prevent unauthenticated or unauthorized users from accessing restricted routes. It does this by implementing the CanActivate interface that allows the guard to decide if a route can be activated.

If the method returns true the request is from a authenticated user or else the route is blocked. Use below code to implement this interface.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Injectable({
  providedIn: 'root'
})
export class AuthService implements CanActivate {

  constructor(private router:Router , private accountService:AccountService) { }
  
  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean|UrlTree>|Promise<boolean|UrlTree>|boolean|UrlTree {

    if(localStorage.getItem('user')!=undefined && (JSON.parse(localStorage.getItem('user'))).clientPrincipal!=null)
    {
     return true;
    }

    return this.accountService.login().pipe(
      map(x=>
      {        

        console.log("response from login method: "+ JSON.stringify(x));
        
        localStorage.setItem('user', JSON.stringify(x));
       
        const user=this.accountService.UserDetails;
              
        console.log("clientprincipal: "+JSON.stringify(user));        

        if(user && user.clientPrincipal) {

          return true;
        }        
        
        window.location.replace('/.auth/login/aad');

        return false;
      }
    ));

  }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
const routes: Routes = [
  {
    path: '',
    component: BaseLayoutComponent,
    children: [

      // Dashboads

      {path: '', component: SessionsComponent, data: {extraParameter: 'dashboardsMenu'},canActivate: [AuthService]},
      {path: 'session/my-sessions', component: MySessionsComponent, data: {extraParameter: 'sessionMenu'},canActivate: [AuthService]},
      {path: 'session/start-session', component: StartSessionsComponent, data: {extraParameter: 'sessionMenu'},canActivate: [AuthService]},
      {path: 'session/join-session', component: JoinSessionsComponent, data: {extraParameter: 'sessionMenu'},canActivate: [AuthService]},
      {path: 'session/add', component: AddSessionsComponent, data: {extraParameter: 'sessionMenu'},canActivate: [AuthService]}
    ]
  }
];

Please go ahead and join our discord channel (https://discord.gg/8Cs82yNS) to give some valuable feedbacks