-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathLtiAccessTokenController.cs
More file actions
98 lines (81 loc) · 3.29 KB
/
LtiAccessTokenController.cs
File metadata and controls
98 lines (81 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Threading.Tasks;
using HwProj.APIGateway.API.Lti.Configuration;
using HwProj.APIGateway.API.Lti.Services;
using HwProj.APIGateway.API.LTI.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
namespace HwProj.APIGateway.API.Lti.Controllers;
[Route("api/lti")]
[ApiController]
public class LtiAccessTokenController(
IOptions<LtiPlatformConfig> options,
ILtiToolService toolService,
ILtiKeyService ltiKeyService,
ILtiTokenService tokenService
) : ControllerBase
{
[HttpPost("token")]
[AllowAnonymous]
public async Task<IActionResult> GetTokenAsync([FromForm] IFormCollection form)
{
if (!form.TryGetValue("grant_type", out var grantType) || grantType != "client_credentials")
{
return BadRequest(new { error = "unsupported_grant_type", error_description = "Only 'client_credentials' is supported." });
}
if (!form.TryGetValue("client_assertion_type", out var assertionType) ||
assertionType != "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
{
return BadRequest(new { error = "invalid_request", error_description = "Invalid client_assertion_type." });
}
if (!form.TryGetValue("client_assertion", out var clientAssertion))
{
return BadRequest(new { error = "invalid_request", error_description = "Missing client_assertion." });
}
var handler = new JwtSecurityTokenHandler();
if (!handler.CanReadToken(clientAssertion))
{
return BadRequest(new { error = "invalid_client", error_description = "Invalid JWT structure." });
}
var unverifiedToken = handler.ReadJwtToken(clientAssertion);
var clientId = unverifiedToken.Issuer;
var tool = toolService.GetByClientId(clientId);
if (tool == null)
{
return Unauthorized(new { error = "invalid_client", error_description = $"Unknown clientId: {clientId}" });
}
var signingKeys = await ltiKeyService.GetKeysAsync(tool.JwksEndpoint);
try
{
var tokenEndpointUrl = options.Value.AccessTokenUrl;
handler.ValidateToken(clientAssertion, new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = tool.ClientId,
ValidateAudience = true,
ValidAudience = tokenEndpointUrl,
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(5),
ValidateIssuerSigningKey = true,
IssuerSigningKeys = signingKeys
}, out _);
}
catch (Exception ex)
{
return Unauthorized(new { error = "invalid_client", error_description = $"Token validation failed: {ex.Message}" });
}
const string scope = "https://purl.imsglobal.org/spec/lti-ags/scope/score";
var accessToken = tokenService.GenerateAccessTokenForLti(tool.ClientId, scope);
return Ok(new
{
access_token = accessToken,
token_type = "Bearer",
expires_in = 3600,
scope
});
}
}