Packages
fnord
0.9.25
0.9.40
0.9.39
0.9.38
0.9.37
0.9.36
0.9.35
0.9.34
0.9.33
0.9.32
0.9.31
0.9.30
0.9.29
0.9.28
0.9.27
0.9.26
0.9.25
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.99
0.8.98
0.8.97
0.8.96
0.8.95
0.8.94
0.8.93
0.8.92
0.8.91
0.8.90
0.8.89
0.8.88
0.8.87
0.8.86
0.8.85
0.8.84
0.8.83
0.8.82
0.8.81
0.8.80
0.8.79
0.8.78
0.8.77
0.8.76
0.8.75
0.8.74
0.8.73
0.8.72
0.8.71
0.8.70
0.8.69
0.8.68
0.8.67
0.8.66
0.8.65
0.8.64
0.8.63
0.8.62
0.8.61
0.8.60
0.8.59
0.8.58
0.8.57
0.8.56
0.8.55
0.8.54
0.8.53
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.47
0.8.46
0.8.45
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.1
0.8.0
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.3
0.7.2
0.7.1
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
AI code archaeology
Current section
Files
Jump to
Current section
Files
lib/mcp/oauth2/adapter/default.ex
defmodule MCP.OAuth2.Adapter.Default do
@moduledoc """
Default OAuth2 Authorization Code + PKCE adapter.
Reserves an ephemeral 127.0.0.1 port, composes the loopback `redirect_uri`,
and delegates to `MCP.OAuth2.Client.start_flow/1`. Maps common provider
rejections (e.g., HTTP 400 for redirect URIs) to actionable error tuples.
Security:
- Avoids logging sensitive values.
- Redirect URIs use 127.0.0.1 ephemeral port per RFC 8252 guidance.
Introduced: M3.
Updated: M7 - Switched from OidccAdapter to pure OAuth2 Client
"""
@behaviour MCP.OAuth2.Adapter
@spec start_flow(map()) ::
{:ok, non_neg_integer(), String.t(), String.t(), String.t(), String.t()}
| {:error, term()}
def start_flow(oauth) when is_map(oauth) do
# Use pre-configured redirect_port if available (for exact URI matching),
# otherwise reserve an ephemeral port
port =
case Map.get(oauth, :redirect_port) do
p when is_integer(p) ->
p
_ ->
{:ok, socket} =
:gen_tcp.listen(0, [
:binary,
{:ip, {127, 0, 0, 1}},
{:active, false},
{:reuseaddr, true}
])
{:ok, {_addr, ephemeral_port}} = :inet.sockname(socket)
:gen_tcp.close(socket)
ephemeral_port
end
# Use localhost instead of 127.0.0.1 to match common registration patterns
redirect_uri = "http://localhost:#{port}/callback"
oauth2 = Map.put(oauth, :redirect_uri, redirect_uri)
case MCP.OAuth2.Client.start_flow(oauth2) do
{:ok, %{auth_url: url, state: state, code_verifier: verifier}} ->
{:ok, port, state, verifier, url, redirect_uri}
{:error, {:http_error, 400}} ->
{:error, {:provider_rejected_redirect, redirect_uri}}
{:error, e} ->
{:error, e}
end
end
end