Skip to main content

API using basic authentication

Platforms:

Example application that exposes an API behind basic authentication

API using basic authentication

This example application deploys an API with a GET route called /user. The route is behind basic authentication and returns a 401 if un-authorized.

In this example a custom BasicAuth class is created. This class exposes a public inflight method (called verify) that is used within the API to verify the request.

INFO

Did you know resources have a preflight and inflight API? Preflight code runs once, at compile time whereas inflight code is run at runtime. In this example we create the BasicAuth and API resources on preflight (default for Wing files) and then use the BasicAuth method (verify) in the API itself (on inflight). To learn more you can read preflight and inflight core concepts.

1bring cloud;
2bring util;
3bring http;
4
5struct Credentials {
6  username: str;
7  password: str;
8}
9
10// Custom class for the authentication logic
11class BasicAuth {
12  user: str;
13  password: str;
14
15  new(user: str?, password: str?) {
16    // Default credentials
17    this.user = user ?? "admin";
18    this.password = password ?? "admin";
19
20    // Custom icon and color for the node
21    nodeof(this).icon = "lock-closed";
22    nodeof(this).color = "red";
23  }
24
25  // public function to verify the requests
26  pub inflight verify(req: cloud.ApiRequest): bool {
27    try {
28      let authHeader = this.authHeader(req.headers);
29      let credentials = this.authCredentials(authHeader);
30      let username = credentials.username;
31      let password = credentials.password;
32      return username == this.user && password == this.password;
33    } catch e {
34      log("exception caught {e}");
35      return false;
36    }
37  }
38
39  // Decodes the given header and returns username and password
40  inflight authCredentials(header: str): Credentials {
41    let auth = util.base64Decode(header.split(" ").at(1));
42    let splittedAuth = auth.split(":");
43    let username = splittedAuth.at(0);
44    let password = splittedAuth.at(1);
45
46    return Credentials {
47      username: username,
48      password: password
49    };
50  }
51  // Returns the authorization header
52  inflight authHeader(headers: Map<str>?): str {
53    if this.authHeaderPresent(headers) {
54      let authHeaderOptional = headers?.tryGet("authorization");
55      let var authHeader = headers?.tryGet("Authorization");
56
57      if (authHeader == nil) {
58        authHeader = authHeaderOptional;
59      }
60
61      return authHeader!;
62    } else {
63      log("headers: {Json.stringify(headers)}");
64      log("no auth header");
65      throw("no auth header");
66    }
67  }
68
69  inflight authHeaderPresent(headers: Map<str>?): bool {
70    if (headers?.has("authorization") == false) && (headers?.has("Authorization") == false) {
71      return false;
72    }
73    return true;
74  }
75
76}
77
78// Create a new instance of the BasicAuth class
79let auth = new BasicAuth() as "Basic auth verification";
80
81// Create a new API 
82let api = new cloud.Api() as "Users API";
83
84// Create the route /user and protect with basic auth
85api.get("/user", inflight (req) => {
86  let authenticated = auth.verify(req);
87
88  if !authenticated {
89    return {
90      status: 401,
91      headers: {
92        "Content-Type" => "text/plain"
93      },
94      body: "Unauthorized"
95    };
96  }
97
98  return {
99    status: 200,
100    headers: {
101      "Content-Type" => "text/plain"
102    },
103    body: Json.stringify({ "firstname": "David", "lastname": "Boyne" })
104  };
105});

Resources used in this example

  • Api - Resource for cloud api