@atproto/oauth-client-expo 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE.txt +7 -0
  3. package/README.md +140 -0
  4. package/android/.editorconfig +2 -0
  5. package/android/build.gradle +47 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/expo/modules/atprotooauthclient/Crypto.kt +69 -0
  8. package/android/src/main/java/expo/modules/atprotooauthclient/ExpoAtprotoOAuthClientModule.kt +41 -0
  9. package/android/src/main/java/expo/modules/atprotooauthclient/Jose.kt +116 -0
  10. package/android/src/main/java/expo/modules/atprotooauthclient/Records.kt +61 -0
  11. package/dist/ExpoAtprotoOAuthClientModule.d.ts +22 -0
  12. package/dist/ExpoAtprotoOAuthClientModule.d.ts.map +1 -0
  13. package/dist/ExpoAtprotoOAuthClientModule.js +3 -0
  14. package/dist/ExpoAtprotoOAuthClientModule.js.map +1 -0
  15. package/dist/ExpoAtprotoOAuthClientModule.types.d.ts +2 -0
  16. package/dist/ExpoAtprotoOAuthClientModule.types.d.ts.map +1 -0
  17. package/dist/ExpoAtprotoOAuthClientModule.types.js +2 -0
  18. package/dist/ExpoAtprotoOAuthClientModule.types.js.map +1 -0
  19. package/dist/expo-oauth-client-interface.d.ts +6 -0
  20. package/dist/expo-oauth-client-interface.d.ts.map +1 -0
  21. package/dist/expo-oauth-client-interface.js +2 -0
  22. package/dist/expo-oauth-client-interface.js.map +1 -0
  23. package/dist/expo-oauth-client-options.d.ts +9 -0
  24. package/dist/expo-oauth-client-options.d.ts.map +1 -0
  25. package/dist/expo-oauth-client-options.js +2 -0
  26. package/dist/expo-oauth-client-options.js.map +1 -0
  27. package/dist/expo-oauth-client.native.d.ts +13 -0
  28. package/dist/expo-oauth-client.native.d.ts.map +1 -0
  29. package/dist/expo-oauth-client.native.js +130 -0
  30. package/dist/expo-oauth-client.native.js.map +1 -0
  31. package/dist/expo-oauth-client.web.d.ts +9 -0
  32. package/dist/expo-oauth-client.web.d.ts.map +1 -0
  33. package/dist/expo-oauth-client.web.js +24 -0
  34. package/dist/expo-oauth-client.web.js.map +1 -0
  35. package/dist/index.d.ts +4 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +2 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/polyfill.d.ts +5 -0
  40. package/dist/polyfill.d.ts.map +1 -0
  41. package/dist/polyfill.js +5 -0
  42. package/dist/polyfill.js.map +1 -0
  43. package/dist/utils/expo-key.d.ts +11 -0
  44. package/dist/utils/expo-key.d.ts.map +1 -0
  45. package/dist/utils/expo-key.js +29 -0
  46. package/dist/utils/expo-key.js.map +1 -0
  47. package/dist/utils/mmkv-simple-store-ttl.d.ts +24 -0
  48. package/dist/utils/mmkv-simple-store-ttl.d.ts.map +1 -0
  49. package/dist/utils/mmkv-simple-store-ttl.js +62 -0
  50. package/dist/utils/mmkv-simple-store-ttl.js.map +1 -0
  51. package/dist/utils/mmkv-simple-store.d.ts +18 -0
  52. package/dist/utils/mmkv-simple-store.d.ts.map +1 -0
  53. package/dist/utils/mmkv-simple-store.js +31 -0
  54. package/dist/utils/mmkv-simple-store.js.map +1 -0
  55. package/dist/utils/stores.d.ts +24 -0
  56. package/dist/utils/stores.d.ts.map +1 -0
  57. package/dist/utils/stores.js +99 -0
  58. package/dist/utils/stores.js.map +1 -0
  59. package/expo-module.config.json +9 -0
  60. package/ios/Crypto.swift +83 -0
  61. package/ios/ExpoAtprotoOAuthClient.podspec +31 -0
  62. package/ios/ExpoAtprotoOAuthClientModule.swift +45 -0
  63. package/ios/Jose.swift +137 -0
  64. package/ios/Records.swift +58 -0
  65. package/package.json +52 -0
  66. package/src/ExpoAtprotoOAuthClientModule.ts +33 -0
  67. package/src/ExpoAtprotoOAuthClientModule.types.ts +2 -0
  68. package/src/expo-oauth-client-interface.ts +10 -0
  69. package/src/expo-oauth-client-options.ts +27 -0
  70. package/src/expo-oauth-client.d.ts +6 -0
  71. package/src/expo-oauth-client.native.ts +111 -0
  72. package/src/expo-oauth-client.web.ts +42 -0
  73. package/src/index.ts +4 -0
  74. package/src/polyfill.ts +4 -0
  75. package/src/utils/expo-key.ts +50 -0
  76. package/src/utils/mmkv-simple-store-ttl.ts +90 -0
  77. package/src/utils/mmkv-simple-store.ts +48 -0
  78. package/src/utils/stores.ts +115 -0
  79. package/tsconfig.build.json +8 -0
  80. package/tsconfig.build.tsbuildinfo +1 -0
  81. package/tsconfig.json +4 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # @atproto/oauth-client-expo
2
+
3
+ ## 0.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#4220](https://github.com/bluesky-social/atproto/pull/4220) [`fefe70126`](https://github.com/bluesky-social/atproto/commit/fefe70126d0ea82507ac750f669b3478290f186b) Thanks [@matthieusieben](https://github.com/matthieusieben)! - OAuthClient SDK for Expo
8
+
9
+ - Updated dependencies [[`fefe70126`](https://github.com/bluesky-social/atproto/commit/fefe70126d0ea82507ac750f669b3478290f186b), [`fefe70126`](https://github.com/bluesky-social/atproto/commit/fefe70126d0ea82507ac750f669b3478290f186b), [`fefe70126`](https://github.com/bluesky-social/atproto/commit/fefe70126d0ea82507ac750f669b3478290f186b), [`09439d7d6`](https://github.com/bluesky-social/atproto/commit/09439d7d688294ad1a0c78a74b901ba2f7c5f4c3)]:
10
+ - @atproto/oauth-client-browser@0.3.33
11
+ - @atproto/oauth-client@0.5.7
package/LICENSE.txt ADDED
@@ -0,0 +1,7 @@
1
+ Dual MIT/Apache-2.0 License
2
+
3
+ Copyright (c) 2022-2025 Bluesky Social PBC, and Contributors
4
+
5
+ Except as otherwise noted in individual files, this software is licensed under the MIT license (<http://opensource.org/licenses/MIT>), or the Apache License, Version 2.0 (<http://www.apache.org/licenses/LICENSE-2.0>).
6
+
7
+ Downstream projects and end users may chose either license individually, or both together, at their discretion. The motivation for this dual-licensing is the additional software patent assurance provided by Apache 2.0.
package/README.md ADDED
@@ -0,0 +1,140 @@
1
+ # Expo Atproto OAuth
2
+
3
+ This is an Expo client library for Atproto OAuth. It implements the required
4
+ native crypto functions for supporting JWTs in React Native and uses the base
5
+ `OAuthClient` interface found in [the Atproto repository](https://github.com/bluesky-social/atproto/tree/main/packages/oauth/oauth-client).
6
+
7
+ ### In bare React Native projects
8
+
9
+ For bare React Native projects, you must ensure that you have [installed and configured the `expo` package](https://docs.expo.dev/bare/installing-expo-modules/)
10
+ before continuing.
11
+
12
+ ## Installation
13
+
14
+ Once you have satisfied the prerequisites, you can simply install the library with `npm install --save @atproto/oauth-client-expo`.
15
+
16
+ ## Usage
17
+
18
+ ### Serve your `oauth-client-metadata.json`
19
+
20
+ You will need to server an `oauth-client-metadata.json` from your application's website. An example of this metadata
21
+ would look like this:
22
+
23
+ ```json
24
+ // assets/oauth-client-metadata.json
25
+ {
26
+ "client_id": "https://example.com/oauth-client-metadata.json",
27
+ "client_name": "React Native OAuth Client Demo",
28
+ "client_uri": "https://example.com",
29
+ "redirect_uris": ["com.example:/auth/callback"],
30
+ "scope": "atproto repo:* rpc:*?aud=did:web:api.bsky.app#bsky_appview",
31
+ "token_endpoint_auth_method": "none",
32
+ "response_types": ["code"],
33
+ "grant_types": ["authorization_code", "refresh_token"],
34
+ "application_type": "native",
35
+ "dpop_bound_access_tokens": true
36
+ }
37
+ ```
38
+
39
+ - The `client_id` should be the same URL as where you are serving your
40
+ `oauth-client-metadata.json` from
41
+ - The `client_uri` can be the home page of where you are serving your metadata
42
+ from
43
+ - Your `redirect_uris` should contain a native redirect URI (for ios/android),
44
+ as well as a web redirect URI (for web).
45
+ - native redirect URI must have a custom scheme, which is formatted as the
46
+ _reverse_ of the domain you are serving the metadata from. Since I am serving
47
+ mine from `example.com`, I use `com.example` as the scheme. If my domain were
48
+ `atproto.expo.dev`, I would use `dev.expo.atproto`. Additionally, the scheme
49
+ _must_ contain _only one trailing slash_ after the `:`. `com.example://` is
50
+ invalid.
51
+ - The `application_type` must be `native`
52
+
53
+ For a real-world example, see [Skylight's client metadata](https://skylight.expo.app/oauth/client-metadata.json).
54
+
55
+ For more information about client metadata, see [the Atproto documentation](https://atproto.com/specs/oauth#client-id-metadata-document).
56
+
57
+ ### Create a client
58
+
59
+ Next, you want to create an `ExpoOAuthClient`. You will need to pass in the same client metadata to the client as you are serving in your `oauth-client-metadata.json`.
60
+
61
+ ```ts
62
+ // utils/oauth-client.ts
63
+ const clientMetadata = require('../assets/oauth-client-metadata.json')
64
+
65
+ const client = new ExpoOAuthClient({
66
+ handleResolver: 'https://bsky.social',
67
+ clientMetadata,
68
+ })
69
+ ```
70
+
71
+ ### Sign a user in
72
+
73
+ Whenever you are ready, you can initiate a sign in attempt for the user using the client using `client.signIn(input)`
74
+
75
+ `input` must be one of the following:
76
+
77
+ - A valid Atproto user handle, e.g. `hailey.bsky.team` or `example.com`
78
+ - A valid DID, e.g. `did:web:example.com` or `did:plc:oisofpd7lj26yvgiivf3lxsi`
79
+ - A valid PDS host, e.g. `https://cocoon.example.com` or `https://bsky.social`
80
+
81
+ > [!NOTE] If you wish to allow a user to _create_ an account instead of signing
82
+ > in, simply use a valid PDS hostname rather than a handle. They will be
83
+ > presented the option to either Sign In with an existing account, or create a
84
+ > new one, on the PDS's sign in page.
85
+
86
+ The response of `signIn` will be a promise resolving to the following:
87
+
88
+ ```ts
89
+ | { status: WebBrowserResultType } // See Expo Web Browser documentation
90
+ | { status: 'error'; error: unknown }
91
+ | { status: 'success'; session: OAuthSession }
92
+ ```
93
+
94
+ For example:
95
+
96
+ ```ts
97
+ try {
98
+ const session = await client.signIn(input ?? '')
99
+ setSession(session)
100
+ const agent = new Agent(session)
101
+ setAgent(agent)
102
+ } catch (err) {
103
+ Alert.alert('Error', String(err))
104
+ }
105
+ ```
106
+
107
+ ### Create an `Agent`
108
+
109
+ To interface with the various Atproto APIs, you will need to create an `Agent`. You will pass your `OAuthSession` to the `Agent` or `XrpcClient` constructor.
110
+
111
+ ```ts
112
+ const agent = new Agent(session)
113
+ // or
114
+ const xrpc = new XrpcClient(session)
115
+ ```
116
+
117
+ Session refreshes will be handled for you for the lifetime of the agent.
118
+
119
+ ### Restoring a session
120
+
121
+ After, for example, closing the application, you will probably need to restore the user's session. You can do this by using the user's DID on the `ExpoOAuthClient`.
122
+
123
+ ```ts
124
+ const session = await client.restore('did:plc:oisofpd7lj26yvgiivf3lxsi')
125
+ const agent = new Agent(session)
126
+ ```
127
+
128
+ If the session needs to be refreshed, `.restore()` will automatically do this for you before returning a session (based on the token's expiration date). In order to force a refresh, you can pass in `true` as the second argument to `restore`.
129
+
130
+ ```ts
131
+ const session = await client.restore(
132
+ 'did:plc:oisofpd7lj26yvgiivf3lxsi',
133
+ true, // force a refresh, ensuring tokens were not revoked
134
+ )
135
+ ```
136
+
137
+ ## Additional Reading
138
+
139
+ - [Atproto OAuth Spec](https://atproto.com/specs/oauth)
140
+ - [Atproto Web OAuth Example](https://github.com/bluesky-social/atproto/tree/main/packages/oauth/oauth-client-browser-example)
@@ -0,0 +1,2 @@
1
+ [*.{kt,kts}]
2
+ indent_size=2
@@ -0,0 +1,47 @@
1
+ apply plugin: 'com.android.library'
2
+
3
+ group = 'expo.modules.atprotooauthclient'
4
+ version = '0.1.0'
5
+
6
+ def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
7
+ apply from: expoModulesCorePlugin
8
+ applyKotlinExpoModulesCorePlugin()
9
+ useCoreDependencies()
10
+ useExpoPublishing()
11
+
12
+ // If you want to use the managed Android SDK versions from expo-modules-core, set this to true.
13
+ // The Android SDK versions will be bumped from time to time in SDK releases and may introduce breaking changes in your module code.
14
+ // Most of the time, you may like to manage the Android SDK versions yourself.
15
+ def useManagedAndroidSdkVersions = false
16
+ if (useManagedAndroidSdkVersions) {
17
+ useDefaultAndroidSdkVersions()
18
+ } else {
19
+ buildscript {
20
+ // Simple helper that allows the root project to override versions declared by this library.
21
+ ext.safeExtGet = { prop, fallback ->
22
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
23
+ }
24
+ }
25
+ project.android {
26
+ compileSdkVersion safeExtGet("compileSdkVersion", 34)
27
+ defaultConfig {
28
+ minSdkVersion safeExtGet("minSdkVersion", 21)
29
+ targetSdkVersion safeExtGet("targetSdkVersion", 34)
30
+ }
31
+ }
32
+ }
33
+
34
+ android {
35
+ namespace "expo.modules.atprotooauthclient"
36
+ defaultConfig {
37
+ versionCode 1
38
+ versionName "0.1.0"
39
+ }
40
+ lintOptions {
41
+ abortOnError false
42
+ }
43
+ }
44
+
45
+ dependencies {
46
+ implementation "com.nimbusds:nimbus-jose-jwt:10.3.1"
47
+ }
@@ -0,0 +1,2 @@
1
+ <manifest>
2
+ </manifest>
@@ -0,0 +1,69 @@
1
+ package expo.modules.atprotooauthclient
2
+
3
+ import com.nimbusds.jose.Algorithm
4
+ import com.nimbusds.jose.jwk.Curve
5
+ import com.nimbusds.jose.jwk.ECKey
6
+ import com.nimbusds.jose.jwk.KeyUse
7
+ import com.nimbusds.jose.util.Base64URL
8
+ import expo.modules.atprotooauthclient.EncodedJWK
9
+ import java.security.KeyPairGenerator
10
+ import java.security.MessageDigest
11
+ import java.security.interfaces.ECPrivateKey
12
+ import java.security.interfaces.ECPublicKey
13
+ import java.util.UUID
14
+
15
+ class Crypto {
16
+ fun digest(data: ByteArray): ByteArray {
17
+ val instance = MessageDigest.getInstance("sha256")
18
+ return instance.digest(data)
19
+ }
20
+
21
+ fun getRandomValues(byteLength: Int): ByteArray {
22
+ val random = ByteArray(byteLength)
23
+ java.security.SecureRandom().nextBytes(random)
24
+ return random
25
+ }
26
+
27
+ fun generateJwk(): EncodedJWK {
28
+ val keyIdString = UUID.randomUUID().toString()
29
+
30
+ val keyPairGen = KeyPairGenerator.getInstance("EC")
31
+ keyPairGen.initialize(Curve.P_256.toECParameterSpec())
32
+ val keyPair = keyPairGen.generateKeyPair()
33
+
34
+ val publicKey = keyPair.public as ECPublicKey
35
+ val privateKey = keyPair.private as ECPrivateKey
36
+
37
+ val privateJwk =
38
+ ECKey
39
+ .Builder(Curve.P_256, publicKey)
40
+ .privateKey(privateKey)
41
+ .keyUse(KeyUse.SIGNATURE)
42
+ .keyID(keyIdString)
43
+ .algorithm(Algorithm.parse("ES256"))
44
+ .build()
45
+
46
+ return EncodedJWK().apply {
47
+ kty = privateJwk.keyType.value
48
+ crv = privateJwk.curve.toString()
49
+ kid = keyIdString
50
+ x = privateJwk.x.toString()
51
+ y = privateJwk.y.toString()
52
+ d = privateJwk.d.toString()
53
+ alg = privateJwk.algorithm.name
54
+ }
55
+ }
56
+
57
+ fun decodeJwk(encodedJwk: EncodedJWK): ECKey {
58
+ val xb64url = Base64URL.from(encodedJwk.x)
59
+ val yb64url = Base64URL.from(encodedJwk.y)
60
+ val db64url = Base64URL.from(encodedJwk.d)
61
+ return ECKey
62
+ .Builder(Curve.P_256, xb64url, yb64url)
63
+ .d(db64url)
64
+ .keyUse(KeyUse.SIGNATURE)
65
+ .keyID(encodedJwk.kid)
66
+ .algorithm(Algorithm.parse(encodedJwk.alg))
67
+ .build()
68
+ }
69
+ }
@@ -0,0 +1,41 @@
1
+ package expo.modules.atprotooauthclient
2
+
3
+ import expo.modules.atprotooauthclient.Crypto
4
+ import expo.modules.atprotooauthclient.Jose
5
+ import expo.modules.kotlin.modules.Module
6
+ import expo.modules.kotlin.modules.ModuleDefinition
7
+
8
+ class ExpoAtprotoOAuthClientModule : Module() {
9
+ override fun definition() =
10
+ ModuleDefinition {
11
+ Name("ExpoAtprotoOAuthClient")
12
+
13
+ AsyncFunction("digest") { data: ByteArray, algo: String ->
14
+ if (algo != "sha256") {
15
+ throw IllegalArgumentException("Unsupported algorithm: $algo")
16
+ }
17
+ return@AsyncFunction Crypto().digest(data)
18
+ }
19
+
20
+ AsyncFunction("getRandomValues") { byteLength: Int ->
21
+ return@AsyncFunction Crypto().getRandomValues(byteLength)
22
+ }
23
+
24
+ AsyncFunction("generatePrivateJwk") { algo: String ->
25
+ if (algo != "ES256") {
26
+ throw IllegalArgumentException("Unsupported algorithm: $algo")
27
+ }
28
+ return@AsyncFunction Crypto().generateJwk()
29
+ }
30
+
31
+ AsyncFunction("createJwt") { header: String, payload: String, encodedJwk: EncodedJWK ->
32
+ val jwk = Crypto().decodeJwk(encodedJwk)
33
+ return@AsyncFunction Jose().createJwt(header, payload, jwk)
34
+ }
35
+
36
+ AsyncFunction("verifyJwt") { token: String, encodedJwk: EncodedJWK, options: VerifyOptions ->
37
+ val jwk = Crypto().decodeJwk(encodedJwk)
38
+ return@AsyncFunction Jose().verifyJwt(token, jwk, options)
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,116 @@
1
+ package expo.modules.atprotooauthclient
2
+
3
+ import com.nimbusds.jose.JWSHeader
4
+ import com.nimbusds.jose.crypto.ECDSASigner
5
+ import com.nimbusds.jose.crypto.ECDSAVerifier
6
+ import com.nimbusds.jose.jwk.ECKey
7
+ import com.nimbusds.jwt.JWTClaimsSet
8
+ import com.nimbusds.jwt.SignedJWT
9
+ import expo.modules.atprotooauthclient.VerifyOptions
10
+ import expo.modules.atprotooauthclient.VerifyResult
11
+
12
+ class InvalidPayloadException(
13
+ message: String,
14
+ ) : Exception(message)
15
+
16
+ class Jose {
17
+ fun createJwt(
18
+ header: String,
19
+ payload: String,
20
+ jwk: ECKey,
21
+ ): String {
22
+ val parsedHeader = JWSHeader.parse(header)
23
+ val parsedPayload = JWTClaimsSet.parse(payload)
24
+
25
+ val signer = ECDSASigner(jwk)
26
+ val jwt = SignedJWT(parsedHeader, parsedPayload)
27
+ jwt.sign(signer)
28
+
29
+ return jwt.serialize()
30
+ }
31
+
32
+ fun verifyJwt(
33
+ token: String,
34
+ jwk: ECKey,
35
+ options: VerifyOptions,
36
+ ): VerifyResult {
37
+ val jwt = SignedJWT.parse(token)
38
+ val verifier = ECDSAVerifier(jwk)
39
+
40
+ if (!jwt.verify(verifier)) {
41
+ throw InvalidPayloadException("invalid JWT signature")
42
+ }
43
+
44
+ val protectedHeader = emptyMap<String, Any>().toMutableMap()
45
+ protectedHeader["alg"] = jwt.header.algorithm
46
+
47
+ jwt.header.getCustomParam("jku")?.let {
48
+ protectedHeader["jku"] = it.toString()
49
+ }
50
+ jwt.header.keyID?.let {
51
+ protectedHeader["kid"] = it
52
+ }
53
+ jwt.header.type?.let {
54
+ protectedHeader["typ"] = it.toString()
55
+ }
56
+ jwt.header.contentType?.let {
57
+ protectedHeader["cty"] = it
58
+ }
59
+ jwt.header.criticalParams?.let {
60
+ protectedHeader["crit"] = it.toList()
61
+ }
62
+
63
+ options.typ?.let {
64
+ if (jwt.header.type.toString() != it) {
65
+ throw InvalidPayloadException("typ mismatch")
66
+ }
67
+ }
68
+
69
+ val claims = jwt.jwtClaimsSet
70
+
71
+ options.requiredClaims?.let { requiredClaims ->
72
+ requiredClaims.forEach { claim ->
73
+ if (!claims.claims.containsKey(claim)) {
74
+ throw InvalidPayloadException("required claim '$claim' missing")
75
+ }
76
+ }
77
+ }
78
+
79
+ options.audience?.let {
80
+ if (!claims.audience.contains(it)) {
81
+ throw InvalidPayloadException("audience mismatch")
82
+ }
83
+ }
84
+
85
+ options.subject?.let {
86
+ if (claims.subject != it) {
87
+ throw InvalidPayloadException("subject mismatch")
88
+ }
89
+ }
90
+
91
+ options.checkTolerance?.let {
92
+ val currentTime = options.currentDate ?: (System.currentTimeMillis() / 1000.0)
93
+ if (claims.issueTime.time / 1000.0 + it < currentTime) {
94
+ throw InvalidPayloadException("token expired")
95
+ }
96
+ }
97
+
98
+ options.maxTokenAge?.let {
99
+ val currentTime = options.currentDate ?: (System.currentTimeMillis() / 1000.0)
100
+ if (claims.issueTime.time / 1000.0 + it < currentTime) {
101
+ throw InvalidPayloadException("token expired")
102
+ }
103
+ }
104
+
105
+ options.issuer?.let {
106
+ if (claims.issuer != it) {
107
+ throw InvalidPayloadException("issuer mismatch")
108
+ }
109
+ }
110
+
111
+ return VerifyResult().apply {
112
+ payload = jwt.payload.toString()
113
+ this.protectedHeader = protectedHeader
114
+ }
115
+ }
116
+ }
@@ -0,0 +1,61 @@
1
+ package expo.modules.atprotooauthclient
2
+
3
+ import expo.modules.kotlin.records.Field
4
+ import expo.modules.kotlin.records.Record
5
+
6
+ class EncodedJWK : Record {
7
+ @Field
8
+ var kty: String = ""
9
+
10
+ @Field
11
+ var crv: String = ""
12
+
13
+ @Field
14
+ var kid: String = ""
15
+
16
+ @Field
17
+ var x: String = ""
18
+
19
+ @Field
20
+ var y: String = ""
21
+
22
+ @Field
23
+ var d: String = ""
24
+
25
+ @Field
26
+ var alg: String = ""
27
+ }
28
+
29
+ class VerifyOptions : Record {
30
+ @Field
31
+ var audience: String? = null
32
+
33
+ @Field
34
+ var checkTolerance: Double? = null
35
+
36
+ @Field
37
+ var issuer: String? = null
38
+
39
+ @Field
40
+ var maxTokenAge: Double? = null
41
+
42
+ @Field
43
+ var subject: String? = null
44
+
45
+ @Field
46
+ var typ: String? = null
47
+
48
+ @Field
49
+ var currentDate: Double? = null
50
+
51
+ @Field
52
+ var requiredClaims: Array<String>? = null
53
+ }
54
+
55
+ class VerifyResult : Record {
56
+ @Field
57
+ var payload: String = ""
58
+
59
+ @Field
60
+ var protectedHeader: Map<String, Any> = emptyMap()
61
+ }
@@ -0,0 +1,22 @@
1
+ import { NativeModule } from 'expo';
2
+ import { SignedJwt, VerifyOptions, VerifyResult } from '@atproto/oauth-client';
3
+ import { ExpoAtprotoOAuthClientModuleEvents } from './ExpoAtprotoOAuthClientModule.types';
4
+ export type NativeJwk = {
5
+ kty: 'EC';
6
+ crv: 'P-256';
7
+ kid: string;
8
+ x: string;
9
+ y: string;
10
+ d: string;
11
+ alg: 'ES256';
12
+ };
13
+ declare class ExpoAtprotoOAuthClientModule extends NativeModule<ExpoAtprotoOAuthClientModuleEvents> {
14
+ digest(data: Uint8Array, algo: string): Promise<Uint8Array>;
15
+ getRandomValues(byteLength: number): Promise<Uint8Array>;
16
+ generatePrivateJwk(algorithm: string): Promise<NativeJwk>;
17
+ createJwt(header: string, payload: string, jwk: NativeJwk): Promise<SignedJwt>;
18
+ verifyJwt<C extends string = never>(token: SignedJwt, jwk: NativeJwk, options: VerifyOptions<C>): Promise<VerifyResult<C>>;
19
+ }
20
+ declare const _default: ExpoAtprotoOAuthClientModule;
21
+ export default _default;
22
+ //# sourceMappingURL=ExpoAtprotoOAuthClientModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoAtprotoOAuthClientModule.d.ts","sourceRoot":"","sources":["../src/ExpoAtprotoOAuthClientModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAA;AACxD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAC9E,OAAO,EAAE,kCAAkC,EAAE,MAAM,sCAAsC,CAAA;AAEzF,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,IAAI,CAAA;IACT,GAAG,EAAE,OAAO,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,GAAG,EAAE,OAAO,CAAA;CACb,CAAA;AAED,OAAO,OAAO,4BAA6B,SAAQ,YAAY,CAAC,kCAAkC,CAAC;IACjG,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAE3D,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAExD,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAEzD,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IAE9E,SAAS,CAAC,CAAC,SAAS,MAAM,GAAG,KAAK,EAChC,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,SAAS,EACd,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;CAC5B;;AAED,wBAEC"}
@@ -0,0 +1,3 @@
1
+ import { requireNativeModule } from 'expo';
2
+ export default requireNativeModule('ExpoAtprotoOAuthClient');
3
+ //# sourceMappingURL=ExpoAtprotoOAuthClientModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoAtprotoOAuthClientModule.js","sourceRoot":"","sources":["../src/ExpoAtprotoOAuthClientModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAA;AA8BxD,eAAe,mBAAmB,CAChC,wBAAwB,CACzB,CAAA","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo'\nimport { SignedJwt, VerifyOptions, VerifyResult } from '@atproto/oauth-client'\nimport { ExpoAtprotoOAuthClientModuleEvents } from './ExpoAtprotoOAuthClientModule.types'\n\nexport type NativeJwk = {\n kty: 'EC'\n crv: 'P-256'\n kid: string\n x: string\n y: string\n d: string\n alg: 'ES256'\n}\n\ndeclare class ExpoAtprotoOAuthClientModule extends NativeModule<ExpoAtprotoOAuthClientModuleEvents> {\n digest(data: Uint8Array, algo: string): Promise<Uint8Array>\n\n getRandomValues(byteLength: number): Promise<Uint8Array>\n\n generatePrivateJwk(algorithm: string): Promise<NativeJwk>\n\n createJwt(header: string, payload: string, jwk: NativeJwk): Promise<SignedJwt>\n\n verifyJwt<C extends string = never>(\n token: SignedJwt,\n jwk: NativeJwk,\n options: VerifyOptions<C>,\n ): Promise<VerifyResult<C>>\n}\n\nexport default requireNativeModule<ExpoAtprotoOAuthClientModule>(\n 'ExpoAtprotoOAuthClient',\n)\n"]}
@@ -0,0 +1,2 @@
1
+ export type ExpoAtprotoOAuthClientModuleEvents = {};
2
+ //# sourceMappingURL=ExpoAtprotoOAuthClientModule.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoAtprotoOAuthClientModule.types.d.ts","sourceRoot":"","sources":["../src/ExpoAtprotoOAuthClientModule.types.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,kCAAkC,GAAG,EAAE,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ExpoAtprotoOAuthClientModule.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoAtprotoOAuthClientModule.types.js","sourceRoot":"","sources":["../src/ExpoAtprotoOAuthClientModule.types.ts"],"names":[],"mappings":"","sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-types\nexport type ExpoAtprotoOAuthClientModuleEvents = {}\n"]}
@@ -0,0 +1,6 @@
1
+ import type { AuthorizeOptions, OAuthClient, OAuthSession } from '@atproto/oauth-client';
2
+ export interface ExpoOAuthClientInterface extends OAuthClient, Disposable {
3
+ signIn(input: string, options?: AuthorizeOptions): Promise<OAuthSession>;
4
+ handleCallback(): Promise<null | OAuthSession>;
5
+ }
6
+ //# sourceMappingURL=expo-oauth-client-interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expo-oauth-client-interface.d.ts","sourceRoot":"","sources":["../src/expo-oauth-client-interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,WAAW,EACX,YAAY,EACb,MAAM,uBAAuB,CAAA;AAE9B,MAAM,WAAW,wBAAyB,SAAQ,WAAW,EAAE,UAAU;IACvE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IACxE,cAAc,IAAI,OAAO,CAAC,IAAI,GAAG,YAAY,CAAC,CAAA;CAC/C"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=expo-oauth-client-interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expo-oauth-client-interface.js","sourceRoot":"","sources":["../src/expo-oauth-client-interface.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n AuthorizeOptions,\n OAuthClient,\n OAuthSession,\n} from '@atproto/oauth-client'\n\nexport interface ExpoOAuthClientInterface extends OAuthClient, Disposable {\n signIn(input: string, options?: AuthorizeOptions): Promise<OAuthSession>\n handleCallback(): Promise<null | OAuthSession>\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type { OAuthClientMetadataInput, OAuthClientOptions, OAuthResponseMode } from '@atproto/oauth-client';
2
+ export type Simplify<T> = {
3
+ [K in keyof T]: T[K];
4
+ } & NonNullable<unknown>;
5
+ export type ExpoOAuthClientOptions = Simplify<{
6
+ clientMetadata: Readonly<OAuthClientMetadataInput>;
7
+ responseMode?: Exclude<OAuthResponseMode, 'form_post'>;
8
+ } & Omit<OAuthClientOptions, 'clientMetadata' | 'responseMode' | 'keyset' | 'runtimeImplementation' | 'sessionStore' | 'stateStore' | 'didCache' | 'handleCache' | 'dpopNonceCache' | 'authorizationServerMetadataCache' | 'protectedResourceMetadataCache'>>;
9
+ //# sourceMappingURL=expo-oauth-client-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expo-oauth-client-options.d.ts","sourceRoot":"","sources":["../src/expo-oauth-client-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,uBAAuB,CAAA;AAE9B,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,WAAW,CAAC,OAAO,CAAC,CAAA;AAEzE,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAC3C;IACE,cAAc,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAA;IAClD,YAAY,CAAC,EAAE,OAAO,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAA;CACvD,GAAG,IAAI,CACN,kBAAkB,EAChB,gBAAgB,GAChB,cAAc,GACd,QAAQ,GACR,uBAAuB,GACvB,cAAc,GACd,YAAY,GACZ,UAAU,GACV,aAAa,GACb,gBAAgB,GAChB,kCAAkC,GAClC,gCAAgC,CACnC,CACF,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=expo-oauth-client-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expo-oauth-client-options.js","sourceRoot":"","sources":["../src/expo-oauth-client-options.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n OAuthClientMetadataInput,\n OAuthClientOptions,\n OAuthResponseMode,\n} from '@atproto/oauth-client'\n\nexport type Simplify<T> = { [K in keyof T]: T[K] } & NonNullable<unknown>\n\nexport type ExpoOAuthClientOptions = Simplify<\n {\n clientMetadata: Readonly<OAuthClientMetadataInput>\n responseMode?: Exclude<OAuthResponseMode, 'form_post'>\n } & Omit<\n OAuthClientOptions,\n | 'clientMetadata'\n | 'responseMode'\n | 'keyset'\n | 'runtimeImplementation'\n | 'sessionStore'\n | 'stateStore'\n | 'didCache'\n | 'handleCache'\n | 'dpopNonceCache'\n | 'authorizationServerMetadataCache'\n | 'protectedResourceMetadataCache'\n >\n>\n"]}
@@ -0,0 +1,13 @@
1
+ import './polyfill';
2
+ import { AuthorizeOptions, OAuthClient, OAuthSession } from '@atproto/oauth-client';
3
+ import { ExpoOAuthClientInterface } from './expo-oauth-client-interface';
4
+ import { ExpoOAuthClientOptions } from './expo-oauth-client-options';
5
+ export declare const CUSTOM_URI_SCHEME_REGEX: RegExp;
6
+ export declare class ExpoOAuthClient extends OAuthClient implements ExpoOAuthClientInterface {
7
+ #private;
8
+ constructor(options: ExpoOAuthClientOptions);
9
+ handleCallback(): Promise<null | OAuthSession>;
10
+ signIn(input: string, options?: AuthorizeOptions): Promise<OAuthSession>;
11
+ [Symbol.dispose](): void;
12
+ }
13
+ //# sourceMappingURL=expo-oauth-client.native.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expo-oauth-client.native.d.ts","sourceRoot":"","sources":["../src/expo-oauth-client.native.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,CAAA;AAGnB,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,YAAY,EACb,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAYpE,eAAO,MAAM,uBAAuB,QAA0C,CAAA;AAG9E,qBAAa,eACX,SAAQ,WACR,YAAW,wBAAwB;;gBAIvB,OAAO,EAAE,sBAAsB;IA8BrC,cAAc,IAAI,OAAO,CAAC,IAAI,GAAG,YAAY,CAAC;IAI9C,MAAM,CACV,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,YAAY,CAAC;IAuCxB,CAAC,MAAM,CAAC,OAAO,CAAC;CAGjB"}