Coverage for gws-app/gws/plugin/auth_method/token/__init__.py: 100%

37 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-05 13:35 +0200

1"""HTTP token authentication method. 

2 

3The client passes a token in an HTTP header. The method reads the configured 

4header, checks the optional prefix and passes the token to the authentication 

5providers as ``token`` credentials. For an authenticated user, the token is 

6stored in ``user.authToken`` and a transient session is opened. No cookie is 

7set. 

8 

9The prefix is compared case-insensitively. Without a prefix, the header value 

10must be the token alone. 

11 

12Example:: 

13 

14 auth.methods+ { 

15 type "token" 

16 header "X-My-Auth" 

17 prefix "Bearer" 

18 } 

19 

20With this configuration, the application expects a header like 

21``X-My-Auth: Bearer <token>``. 

22""" 

23 

24import gws 

25import gws.base.auth 

26import gws.base.web 

27 

28 

29@gws.ext.config.authMethod('token') 

30class Config(gws.base.auth.method.Config): 

31 """Authentication with a token passed in an HTTP header.""" 

32 

33 header: str 

34 """HTTP header that carries the token.""" 

35 prefix: str = '' 

36 """Prefix expected before the token in the header value.""" 

37 

38 

39@gws.ext.object.authMethod('token') 

40class Object(gws.base.auth.method.Object): 

41 """HTTP token authentication method.""" 

42 

43 header: str 

44 """Name of the HTTP header that carries the token.""" 

45 prefix: str 

46 """Prefix expected before the token, empty if none.""" 

47 

48 def configure(self): 

49 self.uid = 'gws.plugin.auth_method.token' 

50 self.header = self.cfg('header') 

51 self.prefix = self.cfg('prefix', default='') 

52 

53 ## 

54 

55 def open_session(self, req): 

56 am = self.root.app.authMgr 

57 credentials = self._parse_header(req) 

58 if not credentials: 

59 return 

60 user = am.authenticate(self, credentials, req) 

61 if user: 

62 user.authToken = credentials.get('token') 

63 return am.create_transient_session(self, user) 

64 

65 def _parse_header(self, req: gws.WebRequester): 

66 """Extract the token from the configured header.""" 

67 h = req.header(self.header) 

68 if not h: 

69 return 

70 

71 a = h.strip().split() 

72 

73 if self.prefix: 

74 if len(a) != 2 or a[0].lower() != self.prefix.lower(): 

75 return 

76 return gws.Data(token=a[1]) 

77 else: 

78 if len(a) != 1: 

79 return 

80 return gws.Data(token=a[0])