tangled
alpha
login
or
join now
lekkice.moe
/
atex
forked from
comet.sh/atex
0
fork
atom
A set of utilities for working with the AT Protocol in Elixir.
0
fork
atom
overview
issues
pulls
1
pipelines
refactor: add opts argument to Oauth module
lekkice.moe
1 month ago
fdcad938
f3ce4f63
+102
-24
1 changed file
expand all
collapse all
unified
split
lib
atex
oauth.ex
+102
-24
lib/atex/oauth.ex
···
52
52
Get a map cnotaining the client metadata information needed for an
53
53
authorization server to validate this client.
54
54
"""
55
55
-
@spec create_client_metadata() :: map()
56
56
-
def create_client_metadata() do
57
57
-
key = Config.get_key()
55
55
+
@type create_client_metadata_option ::
56
56
+
{:key, JOSE.JWK.t()}
57
57
+
| {:client_id, String.t()}
58
58
+
| {:redirect_uri, String.t()}
59
59
+
| {:extra_redirect_uris, list(String.t())}
60
60
+
| {:scopes, String.t()}
61
61
+
@spec create_client_metadata(list(create_client_metadata_option())) :: map()
62
62
+
def create_client_metadata(opts \\ []) do
63
63
+
opts =
64
64
+
Keyword.validate!(opts,
65
65
+
key: Config.get_key(),
66
66
+
client_id: Config.client_id(),
67
67
+
redirect_uri: Config.redirect_uri(),
68
68
+
extra_redirect_uris: Config.extra_redirect_uris(),
69
69
+
scopes: Config.scopes()
70
70
+
)
71
71
+
72
72
+
key = Keyword.get(opts, :key)
73
73
+
client_id = Keyword.get(opts, :client_id)
74
74
+
redirect_uri = Keyword.get(opts, :redirect_uri)
75
75
+
extra_redirect_uris = Keyword.get(opts, :extra_redirect_uris)
76
76
+
scopes = Keyword.get(opts, :scopes)
77
77
+
58
78
{_, jwk} = key |> JOSE.JWK.to_public_map()
59
79
jwk = Map.merge(jwk, %{use: "sig", kid: key.fields["kid"]})
60
80
61
81
%{
62
62
-
client_id: Config.client_id(),
63
63
-
redirect_uris: [Config.redirect_uri() | Config.extra_redirect_uris()],
82
82
+
client_id: client_id,
83
83
+
redirect_uris: [redirect_uri | extra_redirect_uris],
64
84
application_type: "web",
65
85
grant_types: ["authorization_code", "refresh_token"],
66
66
-
scope: Config.scopes(),
86
86
+
scope: scopes,
67
87
response_type: ["code"],
68
88
token_endpoint_auth_method: "private_key_jwt",
69
89
token_endpoint_auth_signing_alg: "ES256",
···
125
145
- `{:ok, :invalid_par_response}` - Server respondend incorrectly to the request
126
146
- `{:error, reason}` - Error creating authorization URL
127
147
"""
148
148
+
@type create_authorization_url_option ::
149
149
+
{:key, JOSE.JWK.t()}
150
150
+
| {:client_id, String.t()}
151
151
+
| {:redirect_uri, String.t()}
152
152
+
| {:scopes, String.t()}
128
153
@spec create_authorization_url(
129
154
authorization_metadata(),
130
155
String.t(),
131
156
String.t(),
132
132
-
String.t()
157
157
+
String.t(),
158
158
+
list(create_authorization_url_option())
133
159
) :: {:ok, String.t()} | {:error, any()}
134
160
def create_authorization_url(
135
161
authz_metadata,
136
162
state,
137
163
code_verifier,
138
138
-
login_hint
164
164
+
login_hint,
165
165
+
opts \\ []
139
166
) do
167
167
+
opts =
168
168
+
Keyword.validate!(opts,
169
169
+
key: Config.get_key(),
170
170
+
client_id: Config.client_id(),
171
171
+
redirect_uri: Config.redirect_uri(),
172
172
+
scopes: Config.scopes()
173
173
+
)
174
174
+
175
175
+
key = Keyword.get(opts, :key)
176
176
+
client_id = Keyword.get(opts, :client_id)
177
177
+
redirect_uri = Keyword.get(opts, :redirect_uri)
178
178
+
scopes = Keyword.get(opts, :scopes)
179
179
+
140
180
code_challenge = :crypto.hash(:sha256, code_verifier) |> Base.url_encode64(padding: false)
141
141
-
key = get_key()
142
181
143
182
client_assertion =
144
144
-
create_client_assertion(key, Config.client_id(), authz_metadata.issuer)
183
183
+
create_client_assertion(key, client_id, authz_metadata.issuer)
145
184
146
185
body =
147
186
%{
148
187
response_type: "code",
149
149
-
client_id: Config.client_id(),
150
150
-
redirect_uri: Config.redirect_uri(),
188
188
+
client_id: client_id,
189
189
+
redirect_uri: redirect_uri,
151
190
state: state,
152
191
code_challenge_method: "S256",
153
192
code_challenge: code_challenge,
154
154
-
scope: Config.scopes(),
193
193
+
scope: scopes,
155
194
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
156
195
client_assertion: client_assertion,
157
196
login_hint: login_hint
···
160
199
case Req.post(authz_metadata.par_endpoint, form: body) do
161
200
{:ok, %{body: %{"request_uri" => request_uri}}} ->
162
201
query =
163
163
-
%{client_id: Config.client_id(), request_uri: request_uri}
202
202
+
%{client_id: client_id, request_uri: request_uri}
164
203
|> URI.encode_query()
165
204
166
205
{:ok, "#{authz_metadata.authorization_endpoint}?#{query}"}
···
192
231
- `{:ok, tokens, nonce}` - Successfully obtained tokens with returned DPoP nonce
193
232
- `{:error, reason}` - Error exchanging code for tokens
194
233
"""
234
234
+
@type validate_authorization_code_option ::
235
235
+
{:key, JOSE.JWK.t()}
236
236
+
| {:client_id, String.t()}
237
237
+
| {:redirect_uri, String.t()}
238
238
+
| {:scopes, String.t()}
195
239
@spec validate_authorization_code(
196
240
authorization_metadata(),
197
241
JOSE.JWK.t(),
198
242
String.t(),
199
199
-
String.t()
243
243
+
String.t(),
244
244
+
list(validate_authorization_code_option())
200
245
) :: {:ok, tokens(), String.t()} | {:error, any()}
201
246
def validate_authorization_code(
202
247
authz_metadata,
203
248
dpop_key,
204
249
code,
205
205
-
code_verifier
250
250
+
code_verifier,
251
251
+
opts \\ []
206
252
) do
207
207
-
key = get_key()
253
253
+
opts =
254
254
+
Keyword.validate!(opts,
255
255
+
key: get_key(),
256
256
+
client_id: Config.client_id(),
257
257
+
redirect_uri: Config.redirect_uri(),
258
258
+
scopes: Config.scopes()
259
259
+
)
260
260
+
261
261
+
key = Keyword.get(opts, :key)
262
262
+
client_id = Keyword.get(opts, :client_id)
263
263
+
redirect_uri = Keyword.get(opts, :redirect_uri)
208
264
209
265
client_assertion =
210
210
-
create_client_assertion(key, Config.client_id(), authz_metadata.issuer)
266
266
+
create_client_assertion(key, client_id, authz_metadata.issuer)
211
267
212
268
body =
213
269
%{
214
270
grant_type: "authorization_code",
215
215
-
client_id: Config.client_id(),
216
216
-
redirect_uri: Config.redirect_uri(),
271
271
+
client_id: client_id,
272
272
+
redirect_uri: redirect_uri,
217
273
code: code,
218
274
code_verifier: code_verifier,
219
275
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
···
245
301
end
246
302
end
247
303
248
248
-
def refresh_token(refresh_token, dpop_key, issuer, token_endpoint) do
249
249
-
key = get_key()
304
304
+
@type refresh_token_option ::
305
305
+
{:key, JOSE.JWK.t()}
306
306
+
| {:client_id, String.t()}
307
307
+
| {:redirect_uri, String.t()}
308
308
+
| {:scopes, String.t()}
309
309
+
@spec refresh_token(
310
310
+
String.t(),
311
311
+
JOSE.JWK.t(),
312
312
+
String.t(),
313
313
+
String.t(),
314
314
+
list(refresh_token_option())
315
315
+
) ::
316
316
+
{:ok, tokens(), String.t()} | {:error, any()}
317
317
+
def refresh_token(refresh_token, dpop_key, issuer, token_endpoint, opts \\ []) do
318
318
+
opts =
319
319
+
Keyword.validate!(opts,
320
320
+
key: get_key(),
321
321
+
client_id: Config.client_id(),
322
322
+
redirect_uri: Config.redirect_uri(),
323
323
+
scopes: Config.scopes()
324
324
+
)
325
325
+
326
326
+
key = Keyword.get(opts, :key)
327
327
+
client_id = Keyword.get(opts, :client_id)
250
328
251
329
client_assertion =
252
252
-
create_client_assertion(key, Config.client_id(), issuer)
330
330
+
create_client_assertion(key, client_id, issuer)
253
331
254
332
body = %{
255
333
grant_type: "refresh_token",
256
334
refresh_token: refresh_token,
257
257
-
client_id: Config.client_id(),
335
335
+
client_id: client_id,
258
336
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
259
337
client_assertion: client_assertion
260
338
}