Example application that exposes an API behind 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