or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

actions-hooks.mdcharts.mdcli-tools.mdconstants-exceptions.mdcore-framework.mddatabase-models.mdforms-fields.mdindex.mdrest-api.mdsecurity.mdviews-crud.md

security.mddocs/

0

# Security System

1

2

Authentication, authorization, and security decorators providing comprehensive user management, role-based permissions, and access control for both traditional views and REST APIs. The security system supports multiple authentication backends and fine-grained permission control.

3

4

## Capabilities

5

6

### Security Decorators

7

8

Decorators that enforce security permissions and access control for view methods and API endpoints.

9

10

```python { .api }

11

from flask_appbuilder.security.decorators import (

12

has_access, has_access_api, protect, permission_name, limit, no_cache

13

)

14

15

@has_access

16

def has_access(f):

17

"""

18

Enable granular security permissions for view methods.

19

Redirects to login page on access denied.

20

21

Usage:

22

@expose('/admin/')

23

@has_access

24

def admin_view(self):

25

return self.render_template('admin.html')

26

"""

27

28

@has_access_api

29

def has_access_api(f):

30

"""

31

Enable security permissions for API methods.

32

Returns HTTP 401/403 on access denied instead of redirect.

33

34

Usage:

35

@expose('/api/data/')

36

@has_access_api

37

def get_data(self):

38

return self.response(200, data={"result": "success"})

39

"""

40

41

@protect(allow_browser_login=False)

42

def protect(allow_browser_login=False):

43

"""

44

Enable security permissions for API methods with JWT support.

45

46

Parameters:

47

- allow_browser_login: Allow Flask-Login session cookies

48

49

Usage:

50

@expose('/api/secure/')

51

@protect()

52

def secure_api(self):

53

return {"message": "JWT authenticated"}

54

55

@expose('/api/browser-ok/')

56

@protect(allow_browser_login=True)

57

def browser_api(self):

58

return {"message": "JWT or session authenticated"}

59

"""

60

61

@permission_name("custom_permission")

62

def permission_name(name):

63

"""

64

Override the permission name for a method.

65

Useful for aggregating methods under single permission.

66

67

Parameters:

68

- name: Custom permission name

69

70

Usage:

71

@expose('/reports/sales/')

72

@has_access

73

@permission_name("can_access_reports")

74

def sales_report(self):

75

return self.render_template('sales.html')

76

77

@expose('/reports/inventory/')

78

@has_access

79

@permission_name("can_access_reports")

80

def inventory_report(self):

81

return self.render_template('inventory.html')

82

"""

83

84

@limit("100/hour", key_func=lambda: request.remote_addr)

85

def limit(limit_value, key_func=None, per_method=False, methods=None,

86

error_message=None, exempt_when=None, override_defaults=True,

87

deduct_when=None, on_breach=None, cost=1):

88

"""

89

Rate limiting decorator for individual routes.

90

91

Parameters:

92

- limit_value: Rate limit string (e.g., "100/hour", "10/minute")

93

- key_func: Function to generate rate limit key

94

- per_method: Apply limit per HTTP method

95

- methods: HTTP methods to apply limit to

96

- error_message: Custom error message

97

- exempt_when: Function to determine exemption

98

- override_defaults: Override default rate limits

99

- deduct_when: Function to determine when to deduct

100

- on_breach: Callback on rate limit breach

101

- cost: Cost per request (default 1)

102

103

Usage:

104

@expose('/api/expensive/')

105

@limit("10/minute")

106

@has_access_api

107

def expensive_operation(self):

108

return {"result": "expensive computation"}

109

"""

110

111

@no_cache

112

def no_cache(view):

113

"""

114

Add no-cache headers to response.

115

116

Usage:

117

@expose('/sensitive-data/')

118

@has_access

119

@no_cache

120

def sensitive_data(self):

121

return self.render_template('sensitive.html')

122

"""

123

```

124

125

### Authentication Constants

126

127

Constants defining supported authentication types and methods.

128

129

```python { .api }

130

from flask_appbuilder.const import (

131

AUTH_OID, AUTH_DB, AUTH_LDAP, AUTH_REMOTE_USER, AUTH_OAUTH

132

)

133

134

# Authentication type constants

135

AUTH_OID = 0 # OpenID authentication

136

AUTH_DB = 1 # Database authentication

137

AUTH_LDAP = 2 # LDAP authentication

138

AUTH_REMOTE_USER = 3 # Remote user authentication (headers)

139

AUTH_OAUTH = 4 # OAuth authentication

140

141

# Usage in configuration

142

AUTH_TYPE = AUTH_DB # Use database authentication

143

AUTH_USER_REGISTRATION = True # Allow user self-registration

144

AUTH_USER_REGISTRATION_ROLE = "Public" # Default role for new users

145

146

# LDAP configuration example

147

AUTH_TYPE = AUTH_LDAP

148

AUTH_LDAP_SERVER = "ldap://ldap.server.com"

149

AUTH_LDAP_BIND_USER = "cn=admin,dc=example,dc=com"

150

AUTH_LDAP_BIND_PASSWORD = "password"

151

AUTH_LDAP_SEARCH = "ou=people,dc=example,dc=com"

152

AUTH_LDAP_UID_FIELD = "uid"

153

154

# OAuth configuration example

155

AUTH_TYPE = AUTH_OAUTH

156

OAUTH_PROVIDERS = [

157

{

158

'name': 'google',

159

'token_key': 'access_token',

160

'icon': 'fa-google',

161

'remote_app': {

162

'client_id': 'your-google-client-id',

163

'client_secret': 'your-google-client-secret',

164

'server_metadata_url': 'https://accounts.google.com/.well-known/openid_configuration',

165

'client_kwargs': {'scope': 'openid email profile'}

166

}

167

}

168

]

169

```

170

171

### Security Manager Integration

172

173

The security manager handles user authentication, authorization, and permission management.

174

175

```python { .api }

176

# Accessing security manager from AppBuilder

177

from flask_appbuilder import AppBuilder

178

179

appbuilder = AppBuilder(app, db.session)

180

security_manager = appbuilder.sm

181

182

# Common security manager methods

183

def get_user_by_id(user_id):

184

"""Get user by ID."""

185

186

def auth_user_db(username, password):

187

"""Authenticate user with database credentials."""

188

189

def auth_user_ldap(username, password):

190

"""Authenticate user with LDAP credentials."""

191

192

def auth_user_oauth(userinfo):

193

"""Authenticate user with OAuth provider info."""

194

195

def add_role(name):

196

"""Add new role to system."""

197

198

def add_permission(name):

199

"""Add new permission to system."""

200

201

def add_permissions_view(permissions_list, view_menu_name):

202

"""Add permissions for a view."""

203

204

def add_permissions_menu(permission_name):

205

"""Add menu permission."""

206

207

def security_cleanup():

208

"""Remove unused permissions."""

209

210

def get_user_menu_access(menu_names=None):

211

"""Get menu items user has access to."""

212

213

# User model properties (when using AUTH_DB)

214

class User(Model):

215

id = Column(Integer, primary_key=True)

216

username = Column(String(64), unique=True, nullable=False)

217

first_name = Column(String(64), nullable=False)

218

last_name = Column(String(64), nullable=False)

219

email = Column(String(120), unique=True, nullable=False)

220

password = Column(String(256))

221

active = Column(Boolean, default=True)

222

created_on = Column(DateTime, default=datetime.datetime.now)

223

changed_on = Column(DateTime, default=datetime.datetime.now)

224

```

225

226

### Permission System

227

228

Flask-AppBuilder uses a comprehensive permission system based on roles and permissions.

229

230

```python { .api }

231

# Permission naming convention

232

# Format: "can_<method_name>" on "<ViewClassName>"

233

234

# Examples of auto-generated permissions:

235

# - "can_list" on "PersonModelView"

236

# - "can_show" on "PersonModelView"

237

# - "can_add" on "PersonModelView"

238

# - "can_edit" on "PersonModelView"

239

# - "can_delete" on "PersonModelView"

240

241

# Custom permissions can be defined:

242

from flask_appbuilder.security.decorators import permission_name

243

244

class MyView(BaseView):

245

@expose('/custom/')

246

@has_access

247

@permission_name("can_access_custom")

248

def custom_method(self):

249

return "Custom functionality"

250

251

# Role management

252

class Role(Model):

253

id = Column(Integer, primary_key=True)

254

name = Column(String(64), unique=True, nullable=False)

255

permissions = relationship("Permission", secondary="ab_permission_view_role")

256

257

# Permission model

258

class Permission(Model):

259

id = Column(Integer, primary_key=True)

260

name = Column(String(100), unique=True, nullable=False)

261

262

# View menu model

263

class ViewMenu(Model):

264

id = Column(Integer, primary_key=True)

265

name = Column(String(250), unique=True, nullable=False)

266

267

# Permission view role association

268

class PermissionViewRole(Model):

269

id = Column(Integer, primary_key=True)

270

permission_view_id = Column(Integer, ForeignKey('ab_permission_view.id'))

271

role_id = Column(Integer, ForeignKey('ab_role.id'))

272

```

273

274

### JWT Authentication

275

276

Support for JSON Web Token authentication for API access.

277

278

```python { .api }

279

# JWT configuration

280

JWT_SECRET_KEY = 'your-jwt-secret-key' # Required for JWT

281

JWT_ACCESS_TOKEN_EXPIRES = datetime.timedelta(hours=1)

282

JWT_REFRESH_TOKEN_EXPIRES = datetime.timedelta(days=30)

283

284

# JWT authentication endpoints (automatically available)

285

# POST /api/v1/security/login - Get JWT tokens

286

# POST /api/v1/security/refresh - Refresh JWT token

287

288

# Using JWT in API requests

289

# Authorization: Bearer <jwt-token>

290

291

# Example API client usage

292

import requests

293

294

# Login to get tokens

295

login_response = requests.post('/api/v1/security/login', json={

296

'username': 'admin',

297

'password': 'password'

298

})

299

tokens = login_response.json()

300

301

# Use access token for API calls

302

headers = {'Authorization': f"Bearer {tokens['access_token']}"}

303

api_response = requests.get('/api/v1/myapi/', headers=headers)

304

305

# Refresh token when expired

306

refresh_response = requests.post('/api/v1/security/refresh', json={

307

'refresh_token': tokens['refresh_token']

308

})

309

new_tokens = refresh_response.json()

310

```

311

312

### Security Configuration Options

313

314

Key configuration settings for customizing the security system behavior.

315

316

```python { .api }

317

# Authentication configuration

318

AUTH_TYPE = AUTH_DB # Authentication method

319

AUTH_USER_REGISTRATION = False # Allow user self-registration

320

AUTH_USER_REGISTRATION_ROLE = "Public" # Default role for new users

321

AUTH_ROLES_SYNC_AT_LOGIN = True # Sync roles at each login (LDAP/OAuth)

322

323

# Password policy

324

AUTH_PASSWORD_COMPLEXITY_ENABLED = True

325

AUTH_PASSWORD_COMPLEXITY_VALIDATOR = r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$"

326

327

# Session configuration

328

PERMANENT_SESSION_LIFETIME = datetime.timedelta(hours=1)

329

SESSION_COOKIE_HTTPONLY = True

330

SESSION_COOKIE_SECURE = True # HTTPS only

331

SESSION_COOKIE_SAMESITE = 'Lax'

332

333

# CSRF protection

334

WTF_CSRF_ENABLED = True

335

WTF_CSRF_TIME_LIMIT = 3600 # 1 hour

336

337

# Rate limiting

338

RATELIMIT_ENABLED = True

339

RATELIMIT_STORAGE_URL = "redis://localhost:6379"

340

341

# OAuth specific settings

342

AUTH_OAUTH_USER_INFO_KEY_USERNAME = "email" # Map OAuth field to username

343

AUTH_OAUTH_USER_INFO_KEY_EMAIL = "email"

344

AUTH_OAUTH_USER_INFO_KEY_FIRST_NAME = "given_name"

345

AUTH_OAUTH_USER_INFO_KEY_LAST_NAME = "family_name"

346

347

# API security

348

FAB_API_SWAGGER_UI = True # Enable Swagger UI

349

FAB_API_SHOW_STACKTRACE = False # Hide stacktraces in production

350

```