or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

basic-auth.mdbearer-auth.mdform-session-auth.mdindex.mdjvm-features.mdoauth.md

bearer-auth.mddocs/

0

# Bearer Authentication

1

2

Bearer token authentication for API access tokens, JWT tokens, and other token-based authentication schemes. This provider extracts bearer tokens from the `Authorization` header and validates them using a custom authentication function.

3

4

## Configuration

5

6

```kotlin { .api }

7

fun AuthenticationConfig.bearer(

8

name: String? = null,

9

configure: BearerAuthenticationProvider.Config.() -> Unit

10

)

11

12

@KtorDsl

13

class BearerAuthenticationProvider.Config(name: String?) : AuthenticationProvider.Config(name) {

14

var realm: String?

15

var authHeader: (ApplicationCall) -> HttpAuthHeader?

16

fun authenticate(body: suspend ApplicationCall.(BearerTokenCredential) -> Any?)

17

fun challenge(body: ChallengeFunction)

18

fun skipWhen(predicate: ApplicationCallPredicate)

19

fun authSchemes(defaultScheme: String, vararg additionalSchemes: String)

20

}

21

```

22

23

### Configuration Properties

24

25

- **`realm`**: Optional authentication realm for challenge responses

26

- **`authHeader`**: Custom function to extract auth header from request

27

28

### Configuration Functions

29

30

- **`authenticate`**: Suspend function that validates bearer token and returns a principal

31

- **`challenge`**: Custom challenge function for authentication failures

32

- **`skipWhen`**: Predicate to skip authentication for certain calls

33

- **`authSchemes`**: Configure supported authentication schemes (default: "Bearer")

34

35

## Basic Usage

36

37

```kotlin

38

install(Authentication) {

39

bearer("auth-bearer") {

40

realm = "Access to the API"

41

authenticate { tokenCredentials ->

42

if (tokenCredentials.token == "valid-token") {

43

UserIdPrincipal("user")

44

} else {

45

null

46

}

47

}

48

}

49

}

50

51

routing {

52

authenticate("auth-bearer") {

53

get("/api/protected") {

54

val principal = call.principal<UserIdPrincipal>()

55

call.respond("Access granted to ${principal?.name}")

56

}

57

}

58

}

59

```

60

61

## JWT Token Validation

62

63

```kotlin

64

bearer("jwt-auth") {

65

realm = "JWT Protected API"

66

authenticate { tokenCredentials ->

67

try {

68

val jwt = JWT.require(Algorithm.HMAC256("secret"))

69

.build()

70

.verify(tokenCredentials.token)

71

72

UserIdPrincipal(jwt.getClaim("username").asString())

73

} catch (exception: JWTVerificationException) {

74

null

75

}

76

}

77

}

78

```

79

80

## API Key Authentication

81

82

```kotlin

83

bearer("api-key-auth") {

84

realm = "API Key Required"

85

authenticate { tokenCredentials ->

86

val apiKey = tokenCredentials.token

87

if (apiKeyService.isValid(apiKey)) {

88

val user = apiKeyService.getUser(apiKey)

89

UserIdPrincipal(user.id)

90

} else {

91

null

92

}

93

}

94

}

95

```

96

97

## Custom Header Extraction

98

99

```kotlin

100

bearer("custom-header") {

101

authHeader { call ->

102

// Extract token from custom header

103

val token = call.request.headers["X-API-Token"]

104

token?.let { HttpAuthHeader.Single("Bearer", it) }

105

}

106

authenticate { tokenCredentials ->

107

validateCustomToken(tokenCredentials.token)

108

}

109

}

110

```

111

112

## API Reference

113

114

### Provider Class

115

116

```kotlin { .api }

117

class BearerAuthenticationProvider internal constructor(

118

config: Config

119

) : AuthenticationProvider(config)

120

```

121

122

### Credential Type

123

124

```kotlin { .api }

125

data class BearerTokenCredential(val token: String)

126

```

127

128

### Authentication Function Type

129

130

```kotlin { .api }

131

typealias AuthenticationFunction<C> = suspend ApplicationCall.(C) -> Any?

132

```

133

134

### Header Extraction Function Type

135

136

```kotlin { .api }

137

typealias AuthHeaderFunction = (ApplicationCall) -> HttpAuthHeader?

138

```

139

140

## Advanced Configuration

141

142

### Multi-Token Support

143

144

```kotlin

145

bearer("multi-token") {

146

authenticate { tokenCredentials ->

147

when {

148

tokenCredentials.token.startsWith("jwt_") ->

149

validateJWT(tokenCredentials.token.removePrefix("jwt_"))

150

tokenCredentials.token.startsWith("api_") ->

151

validateApiKey(tokenCredentials.token.removePrefix("api_"))

152

else -> null

153

}

154

}

155

}

156

```

157

158

### Token Refresh Integration

159

160

```kotlin

161

bearer("refreshable-token") {

162

authenticate { tokenCredentials ->

163

val token = tokenCredentials.token

164

when (val result = tokenService.validateToken(token)) {

165

is TokenResult.Valid -> UserIdPrincipal(result.userId)

166

is TokenResult.Expired -> {

167

// Trigger token refresh flow

168

call.response.headers.append("X-Token-Refresh-Required", "true")

169

null

170

}

171

is TokenResult.Invalid -> null

172

}

173

}

174

}

175

```

176

177

### Custom Challenge Response

178

179

```kotlin

180

bearer("custom-challenge") {

181

realm = "Protected API"

182

challenge { defaultScheme, realm ->

183

call.respond(

184

HttpStatusCode.Unauthorized,

185

mapOf(

186

"error" -> "invalid_token",

187

"error_description" -> "The access token is invalid or expired"

188

)

189

)

190

}

191

authenticate { tokenCredentials ->

192

validateToken(tokenCredentials.token)

193

}

194

}

195

```

196

197

## Integration Patterns

198

199

### Database Token Validation

200

201

```kotlin

202

bearer("database-tokens") {

203

authenticate { tokenCredentials ->

204

transaction {

205

AccessTokens.select { AccessTokens.token eq tokenCredentials.token }

206

.singleOrNull()

207

?.let { tokenRow ->

208

if (tokenRow[AccessTokens.expiresAt] > Clock.System.now()) {

209

UserIdPrincipal(tokenRow[AccessTokens.userId])

210

} else {

211

null

212

}

213

}

214

}

215

}

216

}

217

```

218

219

### OAuth 2.0 Access Token Validation

220

221

```kotlin

222

bearer("oauth2-token") {

223

authenticate { tokenCredentials ->

224

val introspectionResponse = httpClient.post("${oauthServer}/introspect") {

225

parameter("token", tokenCredentials.token)

226

basicAuth(clientId, clientSecret)

227

}.body<IntrospectionResponse>()

228

229

if (introspectionResponse.active) {

230

UserIdPrincipal(introspectionResponse.sub)

231

} else {

232

null

233

}

234

}

235

}

236

```

237

238

## Error Handling

239

240

Bearer authentication uses the standard authentication failure causes:

241

242

```kotlin { .api }

243

sealed class AuthenticationFailedCause {

244

object NoCredentials : AuthenticationFailedCause()

245

object InvalidCredentials : AuthenticationFailedCause()

246

class Error(val message: String) : AuthenticationFailedCause()

247

}

248

```

249

250

Common HTTP responses:

251

- **401 Unauthorized**: When token is missing, invalid, or expired

252

- **403 Forbidden**: When token is valid but lacks required permissions

253

254

## Security Best Practices

255

256

- Use secure token generation with sufficient entropy

257

- Implement token expiration and refresh mechanisms

258

- Store tokens securely (avoid local storage for sensitive tokens)

259

- Use HTTPS to protect tokens in transit

260

- Implement proper token revocation

261

- Consider using short-lived access tokens with refresh tokens

262

- Validate token format and signature before processing

263

- Log authentication failures for security monitoring