npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@atproto/oauth-client-expo

v0.0.5

Published

ATPROTO OAuth client for Expo applications

Readme

Expo Atproto OAuth

This is an Expo client library for Atproto OAuth. It implements the required native crypto functions for supporting JWTs in React Native and uses the base OAuthClient interface found in the Atproto repository.

In bare React Native projects

For bare React Native projects, you must ensure that you have installed and configured the expo package before continuing.

Installation

Once you have satisfied the prerequisites, you can simply install the library with npm install --save @atproto/oauth-client-expo.

Usage

Serve your oauth-client-metadata.json

You will need to server an oauth-client-metadata.json from your application's website. An example of this metadata would look like this:

// assets/oauth-client-metadata.json
{
  "client_id": "https://example.com/oauth-client-metadata.json",
  "client_name": "React Native OAuth Client Demo",
  "client_uri": "https://example.com",
  "redirect_uris": ["com.example:/auth/callback"],
  "scope": "atproto repo:* rpc:*?aud=did:web:api.bsky.app#bsky_appview",
  "token_endpoint_auth_method": "none",
  "response_types": ["code"],
  "grant_types": ["authorization_code", "refresh_token"],
  "application_type": "native",
  "dpop_bound_access_tokens": true
}
  • The client_id should be the same URL as where you are serving your oauth-client-metadata.json from
  • The client_uri can be the home page of where you are serving your metadata from
  • Your redirect_uris should contain a native redirect URI (for ios/android), as well as a web redirect URI (for web).
  • native redirect URI must have a custom scheme, which is formatted as the reverse of the domain you are serving the metadata from. Since I am serving mine from example.com, I use com.example as the scheme. If my domain were atproto.expo.dev, I would use dev.expo.atproto. Additionally, the scheme must contain only one trailing slash after the :. com.example:// is invalid.
  • The application_type must be native

For a real-world example, see Skylight's client metadata.

For more information about client metadata, see the Atproto documentation.

Create a client

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.

// utils/oauth-client.ts
const clientMetadata = require('../assets/oauth-client-metadata.json')

const client = new ExpoOAuthClient({
  handleResolver: 'https://bsky.social',
  clientMetadata,
})

Sign a user in

Whenever you are ready, you can initiate a sign in attempt for the user using the client using client.signIn(input)

input must be one of the following:

  • A valid Atproto user handle, e.g. hailey.bsky.team or example.com
  • A valid DID, e.g. did:web:example.com or did:plc:oisofpd7lj26yvgiivf3lxsi
  • A valid PDS host, e.g. https://cocoon.example.com or https://bsky.social

[!NOTE] If you wish to allow a user to create an account instead of signing in, simply use a valid PDS hostname rather than a handle. They will be presented the option to either Sign In with an existing account, or create a new one, on the PDS's sign in page.

The response of signIn will be a promise resolving to the following:

    | { status: WebBrowserResultType } // See Expo Web Browser documentation
    | { status: 'error'; error: unknown }
    | { status: 'success'; session: OAuthSession }

For example:

try {
  const session = await client.signIn(input ?? '')
  setSession(session)
  const agent = new Agent(session)
  setAgent(agent)
} catch (err) {
  Alert.alert('Error', String(err))
}

Create an Agent

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.

const agent = new Agent(session)
// or
const xrpc = new XrpcClient(session)

Session refreshes will be handled for you for the lifetime of the agent.

Restoring a session

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.

const session = await client.restore('did:plc:oisofpd7lj26yvgiivf3lxsi')
const agent = new Agent(session)

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.

const session = await client.restore(
  'did:plc:oisofpd7lj26yvgiivf3lxsi',
  true, // force a refresh, ensuring tokens were not revoked
)

Additional Reading